การโจมตีจับเวลาในโค้ดระดับแอปพลิเคชัน
เรียนรู้ว่าจังหวะเวลาในการเปรียบเทียบสตริงสามารถรั่วไหลความลับได้อย่างไร และการเปรียบเทียบแบบใช้เวลาคงที่ช่วยป้องกันได้อย่างไร
การโจมตีจับเวลาในโค้ดระดับแอปพลิเคชัน เป็นบทเรียน Cryptology Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Cryptology Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Cryptology Academy มีบทเรียนทั้งหมด 4 บทเรียน
การเปรียบเทียบสตริงที่ใช้เวลาไม่คงที่
ตัวดำเนินการตรวจสอบความเท่ากันของสตริงมาตรฐานในภาษาโปรแกรมส่วนใหญ่จะหยุดทันทีที่พบความไม่ตรงกัน Python ใช้ == กับออบเจ็กต์ไบต์, C ใช้ strcmp และ Java ใช้ String.equals ซึ่งทั้งหมดจะคืนค่าทันทีที่พบไบต์แรกที่แตกต่างกัน สำหรับการเปรียบเทียบสตริงทั่วไป นี่เป็นการเพิ่มประสิทธิภาพ แต่เมื่อเปรียบเทียบค่าลับ เช่น แท็ก MAC หรือรหัสผ่าน จะทำให้เกิดช่องทางด้านข้างจากเวลาที่วัดได้ ซึ่งเปิดเผยข้อมูลบางส่วน
การวัดเวลาการเปรียบเทียบ HMAC
ผู้โจมตีวัดเวลาที่ใช้เปรียบเทียบแท็ก HMAC ที่ส่งมากับค่าที่ถูกต้อง การส่ง HMAC ที่ไบต์แรกตรงกันจะใช้เวลานานกว่าเล็กน้อยเมื่อเทียบกับกรณีที่ไบต์แรกไม่ถูกต้อง เนื่องจากมีการเปรียบเทียบไบต์เพิ่มอีกหนึ่งครั้ง ผู้โจมตีจะส่งค่าที่มีไบต์แรกเป็นไปได้ทุกค่าเป็นจำนวนมากและวัดเวลาตอบสนอง เพื่อระบุไบต์แรกที่ถูกต้อง จากนั้นจะทำซ้ำทีละไบต์จนกู้คืนแท็กได้ครบทั้งหมด
ความแม่นยำของเวลาสำหรับการโจมตีในทางปฏิบัติ
การโจมตีด้วยเวลาผ่านเครือข่ายสมัยใหม่สามารถแยกแยะความแตกต่างของเวลาได้ตั้งแต่หลายสิบถึงหลายร้อยนาโนวินาทีผ่านอินเทอร์เน็ต การเปรียบเทียบ HMAC ขนาด 32 ไบต์ที่ไบต์แต่ละตัวซึ่งถูกต้องเพิ่มเวลาประมวลผลประมาณ 10-100ns จะให้สัญญาณที่วัดได้ หากทำการวัดซ้ำมากพอเพื่อเฉลี่ยความผันผวนของเครือข่าย ในเครือข่ายท้องถิ่น แม้ความแตกต่างเพียงหนึ่งนาโนวินาทีก็อาจถูกใช้ประโยชน์ได้ หากมีการสุ่มตัวอย่างทางสถิติมากเพียงพอ
ช่องโหว่ของตัวดำเนินการ == ใน Python
ใน Python การเปรียบเทียบแท็ก MAC ด้วย == ไม่ปลอดภัย: if mac == submitted_mac จะคืนค่า True หรือ False ตามตำแหน่งที่พบความไม่ตรงกันครั้งแรก ผู้โจมตีสามารถส่งแท็กที่สร้างขึ้นเป็นพิเศษหลายพันรายการและวัดเวลาตอบสนอง เพื่อกู้คืนแท็กที่คาดหวังทีละไบต์ ช่องโหว่นี้เคยปรากฏในแอปพลิเคชันเว็บที่ใช้งานจริง ซึ่งเปรียบเทียบโทเค็นเซสชันหรือคีย์ API อย่างไม่ถูกต้องโดยไม่ใช้ฟังก์ชันแบบเวลาคงที่
hmac.compare_digest ใน Python
hmac.compare_digest(a, b) ของ Python เปรียบเทียบค่าไบต์หรือค่าสตริงสองค่าโดยใช้เวลาคงที่ กล่าวคือใช้เวลาเท่ากันไม่ว่าความไม่ตรงกันครั้งแรกจะเกิดขึ้นที่ตำแหน่งใด ฟังก์ชันนี้พัฒนาด้วย C เพื่อให้ทำงานแบบเวลาคงที่ได้ แม้จะมีค่าใช้จ่ายจากการตีความไบต์โค้ดของ Python ก็ตาม ควรใช้ hmac.compare_digest เสมอเมื่อเปรียบเทียบแท็ก MAC โทเค็นเซสชัน คีย์ API หรือค่าใด ๆ ที่การเปิดเผยข้อมูลด้านเวลาอาจก่อให้เกิดอันตราย
CRYPTO_memcmp ใน OpenSSL
OpenSSL มีฟังก์ชัน CRYPTO_memcmp(a, b, length) สำหรับการเปรียบเทียบหน่วยความจำแบบเวลาคงที่ ต่างจาก memcmp ฟังก์ชันนี้จะประมวลผลไบต์ทั้งหมดตาม length เสมอ ไม่ว่าจะพบความไม่ตรงกันตั้งแต่ต้นหรือไม่ ค่าที่ส่งกลับจะเป็นศูนย์เมื่อค่าเท่ากัน และไม่ใช่ศูนย์เมื่อค่าต่างกัน สิ่งสำคัญคือต้องเปรียบเทียบตามความยาวเต็มที่คาดไว้เสมอ เพราะการเปรียบเทียบค่าที่มีความยาวต่างกันโดยใช้เพียงความยาวที่สั้นกว่าอาจยังเปิดเผยข้อมูลความยาวได้ ควรใช้ CRYPTO_memcmp ในการเปรียบเทียบที่มีความสำคัญด้านความปลอดภัยทุกกรณีในโค้ด C/C++ ที่ใช้ OpenSSL
การโจมตีด้วยเวลาใน RSA: Bleichenbacher
การโจมตีด้วยเวลาไม่ได้จำกัดอยู่แค่การเปรียบเทียบสตริง การโจมตี RSA ของ Bleichenbacher ในปี 2006 ต่อการถอดรหัส RSA PKCS#1 v1.5 แสดงให้เห็นกลไกแยกแยะจากเวลาที่ใช้งานได้จริงต่อการใช้งาน SSL/TLS เวลาที่ใช้ดำเนินการด้วยคีย์ส่วนตัวของ RSA แตกต่างกันตามว่าค่าที่ถอดรหัสมีการเติมข้อมูล PKCS#1 ที่ถูกต้องหรือไม่ ผู้โจมตีสามารถส่งข้อความเข้ารหัสที่สร้างขึ้นเป็นพิเศษหลายพันรายการเพื่อกู้คืนคีย์ส่วนตัวของ RSA ได้ เหตุการณ์นี้เป็นแรงผลักดันให้เกิด RSA-OAEP และการใช้งาน RSA แบบเวลาคงที่
การโจมตีแคชด้วยเวลาใน AES
การใช้งาน AES ที่ใช้ตารางค้นหา ซึ่งพบได้ทั่วไปเพื่อเพิ่มประสิทธิภาพ จะเข้าถึงรายการในตารางที่แตกต่างกันตามคีย์และข้อความต้นฉบับ การพบข้อมูลในแคชและการไม่พบข้อมูลในแคชทำให้เกิดความแตกต่างของเวลาที่วัดได้ ซึ่งเปิดเผยข้อมูลว่ามีการเข้าถึงรายการใดในตาราง ช่องทางด้านข้างนี้อาจเปิดเผยคีย์ AES ได้ วิธีป้องกันคือใช้การใช้งาน AES ที่ไม่พึ่งพาการค้นหาในตาราง เช่น คำสั่งฮาร์ดแวร์ AES-NI หรือการใช้งานซอฟต์แวร์แบบแบ่งบิต
หลักการใช้งานแบบเวลาคงที่
การเขียนโค้ดแบบเวลาคงที่จำเป็นต้องหลีกเลี่ยงสิ่งต่อไปนี้: สาขาเงื่อนไขที่ขึ้นอยู่กับข้อมูลลับ (ให้ใช้การเลือกแบบไร้สาขาร่วมกับการทำมาสก์), รูปแบบการเข้าถึงหน่วยความจำที่ขึ้นอยู่กับข้อมูลลับ (หลีกเลี่ยงตารางค้นหาที่ใช้ค่าลับเป็นดัชนี) และการดำเนินการใด ๆ ที่มีเวลาแฝงขึ้นอยู่กับค่าลับ (เช่น การหารบนตัวประมวลผลบางรุ่น) คอมไพเลอร์อาจปรับแต่งจนส่วนประกอบแบบเวลาคงที่ถูกตัดออก ดังนั้นในส่วนสำคัญอาจจำเป็นต้องใช้แอสเซมบลีหรือการเข้าถึงหน่วยความจำแบบ volatile
AEAD ขจัดการเปรียบเทียบ MAC ระดับแอปพลิเคชัน
วิธีป้องกันการโจมตีด้วยเวลาจากการเปรียบเทียบ MAC ที่ดีที่สุดคือใช้โหมด AEAD (GCM, ChaCha20-Poly1305) และมอบหมายให้ไลบรารีการเข้ารหัสตรวจสอบ MAC การใช้งานในไลบรารีจะตรวจสอบแบบเวลาคงที่อยู่ภายใน หากใช้ AEAD อย่างถูกต้อง (การถอดรหัสล้มเหลวเมื่อมีการแก้ไขใด ๆ และต้องไม่ถอดรหัสก่อนตรวจสอบแท็ก) ก็ไม่จำเป็นต้องเปรียบเทียบแท็ก MAC ในโค้ดแอปพลิเคชันอีกต่อไป จึงขจัดช่องโหว่ด้านเวลาได้ทั้งหมด
การทดสอบช่องโหว่ด้านเวลา
การทดสอบช่องโหว่ด้านเวลาจำเป็นต้องวิเคราะห์การกระจายของเวลาตอบสนองทางสถิติ เครื่องมืออย่าง tlsfuzzer สคริปต์ทดสอบการโจมตีด้วยเวลา และเฟรมเวิร์ก dudect ช่วยตรวจจับความแตกต่างของเวลาในการใช้งานการเข้ารหัสได้ การทดสอบ t กับตัวอย่างเวลาตอบสนองของอินพุตที่ควรใช้เวลาเท่ากันอาจเผยให้เห็นความแตกต่างที่มีนัยสำคัญทางสถิติ ผลลบลวงยังเป็นไปได้ ดังนั้นควรทบทวนโค้ดแบบเวลาคงที่ควบคู่ไปกับการทดสอบด้วย
การเปรียบเทียบแบบเวลาคงที่
ควรใช้ฟังก์ชันใดใน Python เพื่อเปรียบเทียบแท็ก HMAC อย่างปลอดภัยและป้องกันการโจมตีด้วยเวลา
สรุปการโจมตีด้วยเวลา
สรุปการโจมตีด้วยเวลา: การเปรียบเทียบสตริงที่หยุดตั้งแต่เนิ่น ๆ จะเปิดเผยค่าลับทีละไบต์ผ่านความแตกต่างของเวลาตอบสนอง ซึ่งวัดได้ผ่านเครือข่ายเมื่อมีตัวอย่างมากเพียงพอ ให้ใช้ hmac.compare_digest ใน Python และ CRYPTO_memcmp ใน OpenSSL สำหรับการเปรียบเทียบแบบเวลาคงที่ การโจมตีด้วยเวลาจากการเติมข้อมูลของ RSA ทำให้คีย์ส่วนตัวตกอยู่ในความเสี่ยง (ให้ใช้ RSA แบบเวลาคงที่และ OAEP) การโจมตีด้วยเวลาจากการค้นหาในตาราง AES จะเปิดเผยบิตของคีย์ (ให้ใช้ AES-NI หรือการใช้งานแบบแบ่งบิต) และการตรวจสอบโดยไลบรารี AEAD จะขจัดความจำเป็นในการเปรียบเทียบ MAC ระดับแอปพลิเคชัน
คำถามที่พบบ่อย
บทเรียน “การโจมตีจับเวลาในโค้ดระดับแอปพลิเคชัน” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การโจมตีจับเวลาในโค้ดระดับแอปพลิเคชัน” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Cryptology Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Cryptology Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การโจมตีจับเวลาในโค้ดระดับแอปพลิเคชัน”
เรียนรู้ว่าจังหวะเวลาในการเปรียบเทียบสตริงสามารถรั่วไหลความลับได้อย่างไร และการเปรียบเทียบแบบใช้เวลาคงที่ช่วยป้องกันได้อย่างไร คุณปฏิบัติ Cryptology Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Cryptology Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Cryptology Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “การโจมตีจับเวลาในโค้ดระดับแอปพลิเคชัน” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Cryptology Academy นี้ได้ไหม
ได้ บทเรียน Cryptology Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การโจมตี Padding Oracle โดยละเอียด
- การโจมตีแบบเล่นซ้ำและช่องโหว่จากการใช้ Nonce ซ้ำ
- การโจมตีจับเวลาในโค้ดระดับแอปพลิเคชัน
- รูปแบบการใช้งานการเข้ารหัสที่ผิดพลาดที่พบบ่อย