สวัสดี Habr ฉันชื่อ Ilya ฉันทำงานในทีมแพลตฟอร์มที่ Exness เราพัฒนาและใช้งานส่วนประกอบโครงสร้างพื้นฐานหลักที่ทีมพัฒนาผลิตภัณฑ์ของเราใช้
ในบทความนี้ ฉันต้องการแบ่งปันประสบการณ์ของฉันในการใช้เทคโนโลยี SNI ที่เข้ารหัส (ESNI) ในโครงสร้างพื้นฐานของเว็บไซต์สาธารณะ

การใช้เทคโนโลยีนี้จะช่วยเพิ่มระดับความปลอดภัยเมื่อทำงานกับเว็บไซต์สาธารณะ และสอดคล้องกับมาตรฐานความปลอดภัยภายในที่บริษัทนำมาใช้
ก่อนอื่นฉันอยากจะชี้ให้เห็นว่าเทคโนโลยีไม่ได้มาตรฐานและยังอยู่ในร่าง แต่ CloudFlare และ Mozilla รองรับแล้ว (ใน ). สิ่งนี้เป็นแรงบันดาลใจให้เราทำการทดลองเช่นนี้
ทฤษฎีเล็กน้อย
เอสนี่ เป็นส่วนขยายของโปรโตคอล TLS 1.3 ที่อนุญาตการเข้ารหัส SNI ในข้อความ TLS handshake "Client Hello" นี่คือลักษณะของ Client Hello พร้อมการสนับสนุน ESNI (แทนที่จะเป็น SNI ปกติที่เราเห็น ESNI):

หากต้องการใช้ ESNI คุณต้องมีสามองค์ประกอบ:
- ดีเอ็นเอส;
- การสนับสนุนลูกค้า
- การสนับสนุนฝั่งเซิร์ฟเวอร์
DNS
คุณต้องเพิ่มระเบียน DNS สองรายการ – Aและ TXT (บันทึก TXT มีคีย์สาธารณะซึ่งไคลเอ็นต์สามารถเข้ารหัส SNI ได้) - ดูด้านล่าง นอกจากนี้ยังต้องมีการสนับสนุน กระทรวงกลาโหม (DNS ผ่าน HTTPS) เนื่องจากไคลเอนต์ที่มีอยู่ (ดูด้านล่าง) ไม่ได้เปิดใช้งานการสนับสนุน ESNI โดยไม่มี DoH นี่เป็นตรรกะ เนื่องจาก ESNI หมายถึงการเข้ารหัสชื่อของทรัพยากรที่เรากำลังเข้าถึง กล่าวคือ การเข้าถึง DNS ผ่าน UDP นั้นไม่สมเหตุสมผล อีกทั้งการใช้งาน ช่วยให้คุณป้องกันการโจมตีพิษแคชในสถานการณ์นี้
สามารถใช้งานได้ ในหมู่พวกเขา:
CloudFlare (ตรวจสอบเบราว์เซอร์ของฉัน → SNI ที่เข้ารหัส → เรียนรู้เพิ่มเติม) ว่าเซิร์ฟเวอร์ของพวกเขารองรับ ESNI แล้ว นั่นคือสำหรับเซิร์ฟเวอร์ CloudFlare ใน DNS เรามีอย่างน้อยสองบันทึก - A และ TXT ในตัวอย่างด้านล่าง เราค้นหา Google DNS (ผ่าน HTTPS):
А รายการ:
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 บันทึก คำขอจะถูกสร้างขึ้นตามเทมเพลต _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."
}
ดังนั้นจากมุมมองของ DNS เราควรใช้ DoH (ควรใช้กับ DNSSEC) และเพิ่มสองรายการ
สนับสนุนลูกค้า
หากเรากำลังพูดถึงเบราว์เซอร์อยู่ในขณะนี้ . ต่อไปนี้เป็นคำแนะนำเกี่ยวกับวิธีเปิดใช้งานการรองรับ ESNI และ DoH ใน FireFox หลังจากกำหนดค่าเบราว์เซอร์แล้ว เราควรเห็นสิ่งนี้:

เพื่อตรวจสอบเบราว์เซอร์
แน่นอนว่าต้องใช้ TLS 1.3 เพื่อรองรับ ESNI เนื่องจาก ESNI เป็นส่วนเสริมของ TLS 1.3
เพื่อวัตถุประสงค์ในการทดสอบแบ็กเอนด์ด้วยการรองรับ ESNI เราได้ใช้งานไคลเอนต์ go, แต่เพิ่มเติมเกี่ยวกับที่ในภายหลัง.
การสนับสนุนฝั่งเซิร์ฟเวอร์
ปัจจุบัน เว็บเซิร์ฟเวอร์ไม่รองรับ ESNI เช่น nginx/apache ฯลฯ เนื่องจากเว็บเซิร์ฟเวอร์เหล่านี้ทำงานร่วมกับ TLS ผ่าน OpenSSL/BoringSSL ซึ่งไม่รองรับ ESNI อย่างเป็นทางการ
ดังนั้นเราจึงตัดสินใจสร้างส่วนประกอบส่วนหน้าของเราเอง (พร็อกซีย้อนกลับ ESNI) ซึ่งจะสนับสนุนการยกเลิก TLS 1.3 ด้วย ESNI และการรับส่งข้อมูล HTTP(S) พร็อกซีไปยังอัปสตรีม ซึ่งไม่รองรับ ESNI ซึ่งช่วยให้สามารถใช้เทคโนโลยีในโครงสร้างพื้นฐานที่มีอยู่แล้ว โดยไม่ต้องเปลี่ยนส่วนประกอบหลัก นั่นคือ การใช้เว็บเซิร์ฟเวอร์ปัจจุบันที่ไม่รองรับ ESNI
เพื่อความชัดเจน นี่คือแผนภาพ:

ฉันทราบว่าพร็อกซีได้รับการออกแบบให้มีความสามารถในการยุติการเชื่อมต่อ TLS โดยไม่มี ESNI เพื่อรองรับไคลเอนต์ที่ไม่มี ESNI นอกจากนี้ โปรโตคอลการสื่อสารที่มีอัปสตรีมอาจเป็น HTTP หรือ HTTPS ที่มี TLS เวอร์ชันต่ำกว่า 1.3 (หากอัปสตรีมไม่รองรับ 1.3) โครงการนี้ให้ความยืดหยุ่นสูงสุด
การดำเนินการสนับสนุน ESNI บน go เรายืมมาจาก . ฉันต้องการทราบทันทีว่าการใช้งานนั้นค่อนข้างไม่สำคัญ เนื่องจากเกี่ยวข้องกับการเปลี่ยนแปลงในไลบรารีมาตรฐาน การเข้ารหัสลับ/tls และจึงต้องมีการ "แพตช์" โกรูท ก่อนประกอบ.
เพื่อสร้างคีย์ ESNI ที่เราใช้ (ยังเป็นผลงานของ CloudFlare) คีย์เหล่านี้ใช้สำหรับการเข้ารหัส/ถอดรหัส SNI
เราทดสอบการสร้างโดยใช้ Go เวอร์ชัน 1.13 บน Linux (Debian(Alpine) และ MacOS
คำไม่กี่คำเกี่ยวกับคุณสมบัติการดำเนินงาน
พร็อกซีย้อนกลับ ESNI จัดเตรียมตัววัดในรูปแบบ Prometheus เช่น rps เวลาแฝงอัปสตรีมและโค้ดตอบกลับ การแฮนด์เชค TLS ที่ล้มเหลว/สำเร็จ และระยะเวลาการแฮนด์เชค TLS เมื่อมองแวบแรก ดูเหมือนว่าจะเพียงพอที่จะประเมินว่าพร็อกซีจัดการกับการรับส่งข้อมูลอย่างไร
เรายังทำการทดสอบการรับน้ำหนักก่อนการใช้งานด้วย ผลลัพธ์ด้านล่าง:
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
เราทำการทดสอบโหลดเชิงคุณภาพล้วนๆ เพื่อเปรียบเทียบโครงร่างโดยใช้ ESNI Reverse Proxy และไม่ใช้ เรา "เท" การรับส่งข้อมูลในพื้นที่เพื่อกำจัด "การรบกวน" ในส่วนประกอบระดับกลาง
ดังนั้น ด้วยการสนับสนุน ESNI และการใช้พร็อกซีไปยังอัปสตรีมจาก HTTP เราได้ประมาณ ~550 rps จากอินสแตนซ์เดียว โดยมีปริมาณการใช้ CPU/RAM โดยเฉลี่ยของพร็อกซีย้อนกลับ ESNI:
- การใช้งาน CPU 80% (โฮสต์ 4 vCPU, RAM 4 GB) Linux)
- RSS หน่วยความจำ 130 MB

สำหรับการเปรียบเทียบ RPS สำหรับ nginx upstream เดียวกันโดยไม่มีการยกเลิก TLS (โปรโตคอล HTTP) คือ ~ 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
การเกิดข้อความหมดเวลาแสดงว่าทรัพยากรไม่เพียงพอ (เราใช้โฮสต์ที่มี 4 vCPU และ 4 GB RAM) Linuxและในความเป็นจริงแล้ว ศักยภาพในการประมวลผลต่อวินาที (RPS) นั้นสูงกว่า (เราได้รับตัวเลขสูงถึง 2700 RPS จากทรัพยากรที่มีประสิทธิภาพมากกว่า)
โดยสรุปฉันทราบ ว่าเทคโนโลยี ESNI ดูมีแนวโน้มดีทีเดียว ยังคงมีคำถามเปิดอยู่มากมาย เช่น ปัญหาในการจัดเก็บคีย์ ESNI สาธารณะใน DNS และการหมุนเวียนคีย์ ESNI - ปัญหาเหล่านี้กำลังถูกพูดคุยกันอย่างกระตือรือร้นและฉบับร่าง ESNI เวอร์ชันล่าสุด (ณ เวลาที่เขียน) ก็มีอยู่แล้ว .
ที่มา: will.com
