Hello Habr, nama saya Ilya, saya bekerja dalam pasukan platform di Exness. Kami membangunkan dan melaksanakan komponen infrastruktur teras yang digunakan oleh pasukan pembangunan produk kami.
Dalam artikel ini, saya ingin berkongsi pengalaman saya melaksanakan teknologi SNI (ESNI) yang disulitkan dalam infrastruktur laman web awam.

Penggunaan teknologi ini akan meningkatkan tahap keselamatan apabila bekerja dengan laman web awam dan mematuhi piawaian keselamatan dalaman yang diterima pakai oleh Syarikat.
Pertama sekali, saya ingin menyatakan bahawa teknologi itu tidak diseragamkan dan masih dalam draf, tetapi CloudFlare dan Mozilla sudah menyokongnya (dalam ). Ini mendorong kami untuk eksperimen sedemikian.
Sedikit teori
ESNI ialah sambungan kepada protokol TLS 1.3 yang membenarkan penyulitan SNI dalam mesej "Helo Pelanggan" TLS jabat tangan. Inilah rupa Client Hello dengan sokongan ESNI (bukan SNI biasa yang kita lihat ESNI):

Untuk menggunakan ESNI, anda memerlukan tiga komponen:
- DNS;
- Sokongan pelanggan;
- Sokongan sisi pelayan.
DNS
Anda perlu menambah dua rekod DNS - Adan TXT (Rekod TXT mengandungi kunci awam yang digunakan oleh pelanggan untuk menyulitkan SNI) - lihat di bawah. Selain itu, mesti ada sokongan DoH (DNS melalui HTTPS) kerana pelanggan yang tersedia (lihat di bawah) tidak mendayakan sokongan ESNI tanpa DoH. Ini adalah logik, kerana ESNI membayangkan penyulitan nama sumber yang kami akses, iaitu, tidak masuk akal untuk mengakses DNS melalui UDP. Lebih-lebih lagi, penggunaan membolehkan anda melindungi daripada serangan keracunan cache dalam senario ini.
Tersedia pada masa ini , antaranya:
CloudFlare (Semak Penyemak Imbas Saya β SNI Disulitkan β Ketahui Lebih Lanjut) bahawa pelayan mereka sudah menyokong ESNI, iaitu, untuk pelayan CloudFlare dalam DNS kami mempunyai sekurang-kurangnya dua rekod - A dan TXT. Dalam contoh di bawah kami menanyakan Google DNS (melalui HTTPS):
Π entri:
curl 'https://dns.google.com/resolve?name=www.cloudflare.com&type=A'
-s -H 'accept: application/dns+json'
{
"Status": 0,
"TC": false,
"RD": true,
"RA": true,
"AD": true,
"CD": false,
"Question": [
{
"name": "www.cloudflare.com.",
"type": 1
}
],
"Answer": [
{
"name": "www.cloudflare.com.",
"type": 1,
"TTL": 257,
"data": "104.17.210.9"
},
{
"name": "www.cloudflare.com.",
"type": 1,
"TTL": 257,
"data": "104.17.209.9"
}
]
}
TXT rekod, permintaan dijana mengikut templat _esni.FQDN:
curl 'https://dns.google.com/resolve?name=_esni.www.cloudflare.com&type=TXT'
-s -H 'accept: application/dns+json'
{
"Status": 0,
"TC": false,
"RD": true,
"RA": true,
"AD": true,
"CD": false,
"Question": [
{
"name": "_esni.www.cloudflare.com.",
"type": 16
}
],
"Answer": [
{
"name": "_esni.www.cloudflare.com.",
"type": 16,
"TTL": 1799,
"data": ""/wEUgUKlACQAHQAg9SiAYQ9aUseUZr47HYHvF5jkt3aZ5802eAMJPhRz1QgAAhMBAQQAAAAAXtUmAAAAAABe3Q8AAAA=""
}
],
"Comment": "Response from 2400:cb00:2049:1::a29f:209."
}
Jadi, dari perspektif DNS, kita harus menggunakan DoH (sebaik-baiknya dengan DNSSEC) dan menambah dua entri.
Sokongan pengguna
Jika kita bercakap tentang pelayar, maka pada masa ini . Berikut ialah arahan tentang cara mengaktifkan sokongan ESNI dan DoH dalam FireFox. Selepas penyemak imbas dikonfigurasikan, kita akan melihat sesuatu seperti ini:

untuk menyemak pelayar.
Sudah tentu, TLS 1.3 mesti digunakan untuk menyokong ESNI, kerana ESNI ialah lanjutan kepada TLS 1.3.
Untuk tujuan menguji bahagian belakang dengan sokongan ESNI, kami melaksanakan klien pada go, Tetapi lebih lanjut mengenai itu kemudian.
Sokongan sisi pelayan
Pada masa ini, ESNI tidak disokong oleh pelayan web seperti nginx/apache, dsb., kerana ia berfungsi dengan TLS melalui OpenSSL/BoringSSL, yang tidak menyokong ESNI secara rasmi.
Oleh itu, kami memutuskan untuk mencipta komponen bahagian hadapan kami sendiri (proksi terbalik ESNI), yang akan menyokong penamatan TLS 1.3 dengan trafik ESNI dan HTTP(S) proksi ke huluan, yang tidak menyokong ESNI. Ini membolehkan teknologi digunakan dalam infrastruktur yang sedia ada, tanpa mengubah komponen utama - iaitu, menggunakan pelayan web semasa yang tidak menyokong ESNI.
Untuk kejelasan, berikut adalah gambar rajah:

Saya perhatikan bahawa proksi telah direka bentuk dengan keupayaan untuk menamatkan sambungan TLS tanpa ESNI, untuk menyokong pelanggan tanpa ESNI. Selain itu, protokol komunikasi dengan huluan boleh sama ada HTTP atau HTTPS dengan versi TLS lebih rendah daripada 1.3 (jika huluan tidak menyokong 1.3). Skim ini memberikan fleksibiliti maksimum.
Pelaksanaan sokongan ESNI pada go kami meminjam daripada . Saya ingin ambil perhatian segera bahawa pelaksanaan itu sendiri agak tidak penting, kerana ia melibatkan perubahan dalam perpustakaan standard crypto/tls dan oleh itu memerlukan "tampalan" GOROOT sebelum perhimpunan.
Untuk menjana kunci ESNI yang kami gunakan (juga cetusan idea CloudFlare). Kekunci ini digunakan untuk penyulitan/penyahsulitan SNI.
Kami menguji binaan menggunakan go 1.13 pada Linux (Debian, Alpine) dan MacOS.
Beberapa perkataan tentang ciri operasi
Proksi terbalik ESNI menyediakan metrik dalam format Prometheus, seperti rps, kependaman huluan & kod tindak balas, jabat tangan TLS yang gagal/berjaya & tempoh jabat tangan TLS. Pada pandangan pertama, ini nampaknya mencukupi untuk menilai cara proksi mengendalikan trafik.
Kami juga melakukan ujian beban sebelum digunakan. Keputusan di bawah:
wrk -t50 -c1000 -d360s 'https://esni-rev-proxy.npw:443' --timeout 15s
Running 6m test @ https://esni-rev-proxy.npw:443
50 threads and 1000 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 1.77s 1.21s 7.20s 65.43%
Req/Sec 13.78 8.84 140.00 83.70%
206357 requests in 6.00m, 6.08GB read
Requests/sec: 573.07
Transfer/sec: 17.28MB
Kami menjalankan ujian beban kualitatif semata-mata untuk membandingkan skim menggunakan proksi terbalik ESNI dan tanpa. Kami "menuangkan" trafik secara tempatan untuk menghapuskan "gangguan" dalam komponen perantaraan.
Jadi, dengan sokongan ESNI dan proksi ke huluan daripada HTTP, kami menerima kira-kira ~550 rps daripada satu contoh, dengan purata penggunaan CPU/RAM proksi terbalik ESNI:
- Penggunaan CPU 80% (4 vCPU, hos RAM 4 GB, Linux)
- 130 MB Mem RSS

Sebagai perbandingan, RPS untuk hulu nginx yang sama tanpa penamatan TLS (HTTP protocol) ialah ~ 1100:
wrk -t50 -c1000 -d360s 'http://lb.npw:80' β-timeout 15s
Running 6m test @ http://lb.npw:80
50 threads and 1000 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 1.11s 2.30s 15.00s 90.94%
Req/Sec 23.25 13.55 282.00 79.25%
393093 requests in 6.00m, 11.35GB read
Socket errors: connect 0, read 0, write 0, timeout 9555
Non-2xx or 3xx responses: 8111
Requests/sec: 1091.62
Transfer/sec: 32.27MB
Kehadiran tamat masa menunjukkan bahawa terdapat kekurangan sumber (kami menggunakan 4 vCPU, hos RAM 4 GB, Linux), dan sebenarnya potensi RPS adalah lebih tinggi (kami menerima angka sehingga 2700 RPS untuk sumber yang lebih berkuasa).
Kesimpulannya, saya perhatikan bahawa teknologi ESNI kelihatan cukup menjanjikan. Masih terdapat banyak soalan terbuka, contohnya, isu penyimpanan kunci ESNI awam dalam DNS dan kunci ESNI berputar - isu ini sedang dibincangkan secara aktif, dan versi terkini draf ESNI (pada masa penulisan) sudah pun .
Sumber: www.habr.com
