اثر انگشت تی ال اس net.utls
اثر انگشت پیام آغازین TLS: اولین پیام دستدهی TLS 1.3 را با چینش بایت کروم، فایرفاکس یا سافاری بسازید، رشتهی JA3 حساب کنید و از آن دستدهی را اجرا کنید.
واردسازی net.utls
نام آرگومانها شناسهی خود کد است و معادل فارسی ندارد؛ گونهها، کلیدواژهها و نام بستهها با معادل فارسی نوشته میشوند.
دیوار آتشی که ترافیک شما را نمیخواند، هنوز میتواند پیام اول را بخواند. ClientHello یک اتصال TLS رمزها، افزونهها و ترتیبشان، منحنیها و الگوریتمهای امضایی را که کارخواه پشتیبانی میکند فهرست میکند، و هر کتابخانهی TLS این فهرست را به شکل خودش مینویسد. این فهرست یک اثر انگشت است (JA3 شناختهشدهترین راه نوشتنش است) و کارخواه پراکسی که فهرست پیشفرض کتابخانهاش را به کار ببرد اثر انگشتی دارد که هیچ مرورگری ندارد. این بسته خودِ ClientHello را از روی توصیفی که میتوانید بخوانید و عوض کنید میسازد تا چینش یک مرورگر را داشته باشد.
نمایه یک Spec برای یک خانوادهی کارخواه برمیگرداند. ساخت یک مشخصه و چند Options (نام سرور، فهرست ALPN، بر زدن افزونهها) را به یک Hello تبدیل میکند: بایتهای پیام با عدد تصادفی تازه، جفت کلید X25519 تازه و شناسهی نشست تصادفی. پوشش کارخواه سپس روی سوکت وصلشده با آن پیام دستدهی TLS 1.3 را اجرا میکند و یک tls.Conn معمولی برمیگرداند. جی ای سه اثر انگشت هر پیامی را مینویسد و رکورد آن را در یک رکورد TLS میپیچد، مثلاً برای دادن به ابزار تکهتکهکردن سانسورشکن. ریالیتی این بسته را برای پیامی که اثبات خود را در آن مهر میکند به کار میبرد.
نمایهها
| نام | قرار است شبیه چه باشد |
|---|---|
chrome، edge | یک کرومیوم جدید: مقدارهای GREASE، سهم کلید ترکیبی پساکوانتومی، GREASE برای ECH، افزونهی ALPS، فشردهسازی گواهی و پر کردن تا ۵۱۲ بایت در صورت نیاز. |
chrome_120 | نمایهی قدیمی: کرومیومی از پیش از سهم کلید ترکیبی، بدون گروه پساکوانتومی. ایکسری ۲۶.۹.۹ و بعدتر (ریالیتی از ۲۰۲۶-۰۹-۰۸) پیامی را که X25519MLKEM768 ندارد رها میکنند، پس فقط برای کارسازهای قدیمیتر به کار ببرید (با ایکسری ۲۶.۷.۲۸ احراز میشود). در نام نمایهها نیست؛ نام نمایههای قدیمی آن را میآورد. |
firefox | فایرفاکس: بدون GREASE، رمزها به ترتیب خودش، سهم کلید secp256r1 کنار X25519، اعتبارنامههای تفویضی و حد اندازهی رکورد. |
safari، ios | سافاری و iOS: GREASE، فهرست بلندتر رمزهای قدیمیتر، بدون ECH. |
randomized | چینش کروم با افزونهها و رمزهای برزدهشده تا هیچ دو پیامی JA3 یکسان نداشته باشند. |
اینها تقریبهایی هستند که از حافظهی آنچه این کارخواهها میفرستند نوشته شدهاند، نه ضبط واقعی. مقایسه با ضبط مرورگر واقعی اینجا ممکن نبود. ساختار به دو راه سنجیده شد: پیامها با net.censor.ParseClientHello خوانده میشوند و با سرور بستهی tls دستدهی TLS 1.3 واقعی را کامل میکنند. مرورگرها با هر انتشار پیامشان را عوض میکنند، پس نمایه را نقطهی شروع بدانید و Spec را (فهرستهای متنی ساده است) مطابق مرورگر دلخواه ویرایش کنید.
مشخصه چگونه نوشته میشود
فهرستهای Spec متنی از عددهای شانزدهی جداشده با فاصلهاند. g0 تا g4 جایگاههای GREASE هستند که به یک مقدار رزروشدهی تصادفی (0a0a، 1a1a و ...) تبدیل میشوند؛ pad جای افزونهی پرکننده است. extensions ترتیب روی سیم است؛ 0000 نام سرور، 0010 ALPN، 0033 سهم کلید، fe0d GREASE برای ECH و ... . key_shares میگوید کدام سهمها فرستاده شود: 001d X25519 با جفت کلید همان پیام، 0017 سهم secp256r1 با بایت تصادفی و 11ec X25519MLKEM768.
چیزهایی که گیر میاندازند
- سهمهای کلید غیر از X25519 کلیدی پشتشان نیست. سهم secp256r1 بایت تصادفی است و بخش ML-KEM سهم ترکیبی یک کلید کپسولهسازی تصادفیِ خوشساخت است. سروری که یکی از آن گروهها را برگزیند نمیتواند دستدهی را با شما تمام کند؛ برای X25519 میتواند. با
pq = falseگروه ترکیبی را کلاً از پیام کنار بگذارید. - پیام به طور پیشفرض ALPN
h2پیشنهاد میکند. اگر سرور آن را برگزیند با چیزی حرف میزنید که HTTP/2 انتظار دارد. برای انتقال پراکسیalpn = "http/1.1"بگذارید، یا"none"تا افزونه حذف شود. - بعضی بایتها عمداً تصادفیاند. مقدارهای GREASE، طول ECH، عدد تصادفی، شناسهی نشست و سهمهای کلید با هر
ساختعوض میشوند. JA3 مقدارهای GREASE و بایت کلید را نادیده میگیرد، پس JA3 هر نمایه پایدار است. - فقط TLS 1.3 و بدون HelloRetryRequest. دستدهی از پیام سفارشی با پیام روشن شکست میخورد اگر سرور گروه دیگری بخواهد یا فقط TLS 1.2 بداند.
- پیام را آزاد کنید.
Helloمالک بافرهایش است: وقتی تمام کردیدآزادسازی سلامرا صدا بزنید.
ساخت پیام و خواندن JA3
نمونه برای سه نمایه یک پیام با کنار گذاشتن سهم ترکیبی میسازد و رشتههای JA3 را چاپ میکند. رشتهی JA3 نگارش، رمزها، شناسهی افزونهها، منحنیها و قالب نقطههاست، هرکدام به صورت عدد دهدهی و با حذف GREASE. ترتیب شناسهی افزونهها روشنترین تفاوت میان نمایههاست.
// زبان: فارسی
واردسازی شبکه.اثر انگشت تی ال اس
تابع ریشه:
سرچاپ "نمایهها:"، اثر انگشت تی ال اس.نام نمایهها()
ناپایا o := اثر انگشت تی ال اس.گزینهها {}
o.نام کارساز = "www.example.com"
o.کلید پسا کوانتومی = نادرست
هر name در ["chrome"، "firefox"، "safari"]:
ناپایا h := اثر انگشت تی ال اس.ساخت(اثر انگشت تی ال اس.نمایه(name)، o)
سرچاپ name، "پیام آغازین بزرگتر از ۴۰۰ بایت است:"، h.خام.طول بزرگتر 400
سرچاپ اثر انگشت تی ال اس.جی ای سه(h.خام)
اثر انگشت تی ال اس.آزادسازی سلام(h)
پایان
سرچاپ "نمایهی ناشناخته معتبر است:"، اثر انگشت تی ال اس.نمایه("netscape").معتبر
پایاندستدهی از یک نمایه
پوشش کارخواه سوکت وصلشده، مشخصه، گزینهها و یک tls.Config میگیرد. گواهی به شکل عادی بررسی میشود. نتیجه یک tls.Conn است، پس هر تابع tls و پشتیبانی TLS انتقال شبکه با آن کار میکند.
// زبان: فارسی
واردسازی شبکه.تی سی پی
واردسازی شبکه.اثر انگشت تی ال اس
واردسازی تی ال اس
تابع ریشه:
c := تی سی پی.شماره گیری("www.example.com"، 443)
ناپایا o := اثر انگشت تی ال اس.گزینهها {}
o.نام کارساز = "www.example.com"
o.پروتکل برنامه = "http/1.1"
cfg := تی ال اس.پیکربندی جدید("www.example.com")
ناپایا t := اثر انگشت تی ال اس.پوشش کارخواه(c.توصیفگر، اثر انگشت تی ال اس.نمایه("chrome")، o، cfg)
اگر وارونه تی ال اس.اتصال معتبر(t):
سرچاپ "شکست خورد:"، تی ال اس.خطای اتصال(t)
برگشت 1
پایان
تی ال اس.نوشتن(t، "GET / HTTP/1.1\r\nHost: www.example.com\r\nConnection: close\r\n\r\n")
سرچاپ تی ال اس.خواندن(t، 200)
تی ال اس.بستن اتصال(t)
پایانمحدودیتها
- نمایهها تقریباند، نه ضبط. با مرورگر زنده مقایسه نشدند و کارخواههای واقعی از انتشاری به انتشار دیگر تغییر میکنند.
- ML-KEM ندارد. سهم ترکیبی جانگهدار است (بالا را ببینید) و سروری که آن را برگزیند دستدهی را میشکند.
- از سرگیری نشست و افزونهی کلید پیشاشتراکی ندارد. پیام همیشه اتصال اول است.
- افزونهی ECH فقط GREASE است. شکل یکی واقعی را دارد و چیزی در آن رمز نشده.
- لایهی رکورد و دستدهی از کتابخانه است. رکورد اول مثل مرورگرها نگارش قدیمی
0x0301دارد، اما طولها و زمانبندی آنچه پس از پیام میآید مال بستهی tls است، نه مرورگر. - فقط TLS 1.3. سروری که با TLS 1.2 جواب بدهد دستدهی را شکست میدهد.
گونهها
بایتها Bytes
ساختار بایتها| نام | انگلیسی | گونه | توضیح |
|---|---|---|---|
| نشانگر | p | تهی* | ابتدای بایتها. |
| طول | len | صحیح = 0 | چند بایت استفاده شده. |
| ظرفیت | cap | صحیح = 0 | چند بایت گرفته شده. |
مشخصات Spec
ساختار مشخصات| نام | انگلیسی | گونه | توضیح |
|---|---|---|---|
| نام | name | رشته = "" | نام نمایه. |
| رمزها | ciphers | رشته = "" | رمزها به ترتیب، به صورت عدد شانزدهی. g0 مقدار GREASE است. |
| افزونهها | extensions | رشته = "" | شناسهی افزونهها به ترتیب روی سیم. g1 و g4 افزونههای GREASE هستند و pad جای پرکننده. |
| گروهها | groups | رشته = "" | گروههای پشتیبانیشده به ترتیب. |
| سهم کلیدها | key_shares | رشته = "" | سهمهای کلیدی که فرستاده میشود: 001d X25519، 0017 secp256r1، 11ec X25519MLKEM768، g2 GREASE. |
| الگوریتمهای امضا | sigalgs | رشته = "" | الگوریتمهای امضا به ترتیب. |
| نسخهها | versions | رشته = "" | نگارشهای پشتیبانیشده به ترتیب، g3 برای مقدار GREASE. |
| پروتکل برنامه | alpn | رشته = "" | نام پروتکلهای ALPN، جداشده با ویرگول. |
| فشردهسازی گواهی | cert_compress | رشته = "" | الگوریتمهای فشردهسازی گواهی، به صورت عدد شانزدهی. |
| اعتبارنامه تفویضی | delegated | رشته = "" | الگوریتمهای امضای اعتبارنامهی تفویضی، به صورت عدد شانزدهی. |
| حد اندازه رکورد | record_size_limit | صحیح = 0 | مقدار افزونهی حد اندازهی رکورد، ۰ وقتی نمایه ندارد. |
| اندازه پرکننده | pad_to | صحیح = 0 | پیام را وقتی میان ۲۵۶ بایت و این اندازه است تا این اندازه پر کن. ۰ پر کردن را خاموش میکند. |
| تصادفی سازی | randomize | منطقی = نادرست | افزونهها و رمزها را در هر ساخت بر بزن. |
| معتبر | ok | منطقی = نادرست | برای نام نمایهی ناشناخته نادرست است. |
گزینهها Options
ساختار گزینهها| نام | انگلیسی | گونه | توضیح |
|---|---|---|---|
| نام کارساز | server_name | رشته = "" | نام سرور، خالی یعنی هیچ. |
| پروتکل برنامه | alpn | رشته = "" | فهرست ALPN را جایگزین میکند، جداشده با ویرگول. none افزونه را حذف میکند. خالی فهرست نمایه را نگه میدارد. |
| بر زدن افزونهها | shuffle | منطقی = نادرست | ترتیب افزونهها را بر میزند، با نگه داشتن افزونههای GREASE در دو سر و پرکننده در آخر. |
| کلید پسا کوانتومی | pq | منطقی = درست | گروه ترکیبی پساکوانتومی و سهم کلیدش را بگنجان. نادرست آنها را کنار میگذارد. |
| گریس اکو | ech | منطقی = درست | افزونهی GREASE برای ECH را اگر نمایه دارد بگنجان. |
| پرکننده | padding | منطقی = درست | افزونهی پرکننده را اگر نمایه دارد اضافه کن. |
سلام کارخواه Hello
ساختار سلام کارخواه| نام | انگلیسی | گونه | توضیح |
|---|---|---|---|
| خام | raw | بایتها | پیام دستدهی، از بایت نوع به بعد، بدون سرآیند رکورد. |
| کلید خصوصی | priv | بایتها | کلید خصوصی X25519 سهم کلید. |
| کلید عمومی | pub_key | بایتها | کلید عمومی X25519 سهم کلید. |
| بذر پسا کوانتومی | pq_seed | بایتها | بذر ۶۴ بایتی ML-KEM پشت کلید مشترک X25519MLKEM768. اگر پیام آغازین چنین کلیدی نداشته باشد تهی است. |
| کلید عمومی پسا کوانتومی | pq_ek | بایتها | کلید کپسولهسازی ML-KEM-768 که در کلید مشترک رفته است. |
| معتبر | ok | منطقی = نادرست | پیام ساخته شد. |
| خطا | err | رشته = "" | چرا ساخته نشد. |
تابعها
جی ای سه JA3
تابع جی ای سه(b: بایتها): رشتهآزادسازی بایتها FreeBytes
تابع آزادسازی بایتها(b &: بایتها)آزادسازی سلام FreeHello
تابع آزادسازی سلام(h &: سلام کارخواه)به شانزدهی ToHex
تابع به شانزدهی(b: بایتها): رشتهجایگاه شناسه نشست SessionIdOffset
تابع جایگاه شناسه نشست(): صحیحraw شروع میشود.تنظیم شناسه نشست SetSessionId
تابع تنظیم شناسه نشست(h &: سلام کارخواه، sid: تهی*)ساخت Build
تابع ساخت(sp: مشخصات، o: گزینهها): سلام کارخواهنمایه Profile
تابع نمایه(name: رشته): مشخصاتok را بررسی کنید.نام نمایهها ProfileNames
تابع نام نمایهها(): رشتهrandomized روی chrome ساخته شده و سهم کلید ترکیبی هم دارد.نام نمایههای قدیمی LegacyProfileNames
تابع نام نمایههای قدیمی(): رشتهchrome_120 که سهم کلید ترکیبی ندارد و ایکسری ۲۶.۹.۹ و بعدتر آن را نمیپذیرند).رکورد Record
تابع رکورد(h: سلام کارخواه): بایتهابذر پسا کوانتومی سلام PqSeed
تابع بذر پسا کوانتومی سلام(h: سلام کارخواه): تهی*tls.WrapClientRawPq آن را میگیرد.پوشش کارخواه WrapClient
تابع پوشش کارخواه(fd: صحیح۶۴، sp: مشخصات، o: گزینهها، cfg: تی ال اس.پیکربندی): تی ال اس.اتصال