เครื่องมือสำหรับนักพัฒนาซอฟต์แวร์ · URL ตัวเข้ารหัสและตัวถอดรหัส
การเข้ารหัส URL สองเท่า: %2520 เกิดขึ้นได้อย่างไร และจะตรวจจับและเลิกทำได้อย่างไร
· มันทำงานอย่างไร
การเข้ารหัส URL javascript นักพัฒนาเวิร์กโฟลว์ การดีบัก
%2520 ใน URL หมายถึงช่องว่างถูกเข้ารหัสสองครั้ง โพสต์นี้จะอธิบายข้อผิดพลาดไปป์ไลน์ที่เป็นสาเหตุ วิธีจดจำลายเซ็น และจำนวนการถอดรหัสที่ปลอดภัย
การเข้ารหัส URL สองเท่า: เมื่อ %2520 หมายถึงช่องว่างผ่านตัวเข้ารหัสสองตัว
ชื่อไฟล์ที่มาถึงเป็น "my%20file.pdf" แทนที่จะเป็น "my file.pdf" จะส่งสัญญาณการเข้ารหัสสองครั้ง: ช่องว่างถูกเข้ารหัสเป็น %20 จากนั้นเครื่องหมายเปอร์เซ็นต์นั้นถูกเข้ารหัสเป็น %25 ทำให้เกิด %2520 ในตอนสุดท้าย URL แต่ละเลเยอร์ของระบบ เช่น รหัสไคลเอ็นต์ กรอบงานเว็บ หรือพร็อกซีย้อนกลับ อาจเข้ารหัสเพียงครั้งเดียว เมื่อสองชั้นแยกกันเข้ารหัส อักขระตัวเดียวจะเสียหาย
พื้นผิวการเข้ารหัสคู่ส่วนใหญ่มักอยู่ในลูกโซ่การเปลี่ยนเส้นทางและระบบเทมเพลตที่ซับซ้อน นักพัฒนาอาจสร้าง URL ที่เข้ารหัสภายในเฟรมเวิร์กที่เข้ารหัสเอาต์พุตทั้งหมดตามค่าเริ่มต้น พร็อกซีย้อนกลับหรือเครือข่ายการจัดส่งเนื้อหาอาจเข้ารหัส URL ที่ได้รับการเข้ารหัสจากระบบแบ็กเอนด์แล้วอีกครั้ง พารามิเตอร์ที่มีค่าที่เข้ารหัสแล้วจะถูกเข้ารหัสอีกครั้งก่อนที่จะซ้อนอยู่ในโครงสร้าง URL อื่น
เหตุใด %25 จึงเป็นสิ่งที่บอก — เครื่องหมายเปอร์เซ็นต์นั้นได้รับการเข้ารหัส ดังนั้น %20 จึงกลายเป็น %2520 และ %C3%A9 กลายเป็น %25C3%25A9
เครื่องหมายปากโป้งของการเข้ารหัสสองครั้งคือ %25 ปรากฏขึ้นในตำแหน่งที่ปกติแล้วคุณคาดว่าจะเห็นเครื่องหมายเปอร์เซ็นต์เดียวใน URL หรือข้อมูล ใน URL ที่เข้ารหัสตามปกติ คุณจะไม่เห็น %25 เว้นแต่จะส่งตัวอักษร "%25" หากมีการเข้ารหัสช่องว่างที่เข้ารหัสเป็น %20 อีกครั้ง จะกลายเป็น %2520
อักขระเน้นเสียง เช่น é ซึ่งเข้ารหัสตามปกติเป็น %C3%A9 จะกลายเป็น %25C3%25A9 เมื่อเข้ารหัสสองครั้งโดยสองระบบที่แตกต่างกันตามลำดับ การเรียนรู้ที่จะมองเห็นรูปแบบ %25 ในแถบ URL บันทึก และข้อความแสดงข้อผิดพลาด จะช่วยประหยัดเวลานับไม่ถ้วนในการทำงานแก้ไขจุดบกพร่องที่น่าหงุดหงิดในสภาพแวดล้อมการผลิตที่ข้อมูลไหลผ่านบริการต่างๆ
ในกรณีที่มีการใช้การเข้ารหัสสองชั้น — โค้ดไคลเอ็นต์พร้อมเฟรมเวิร์ก การเปลี่ยนเส้นทาง พร็อกซี และตัวช่วยเทมเพลต
การเข้ารหัสสองครั้งจะทำลายทั้งความสามารถในการอ่านและความสามารถของระบบฝั่งเซิร์ฟเวอร์ในการแยกวิเคราะห์ URL อย่างถูกต้อง ไฟล์ชื่อ "my file.pdf" จะกลายเป็น "my%20file.pdf" เมื่อเข้ารหัสอย่างถูกต้อง หากสตริงที่เข้ารหัสถูกเข้ารหัสอีกครั้ง (อาจใช้แบบฟอร์ม) สตริงนั้นจะกลายเป็น "my%2520file.pdf"
เมื่อเซิร์ฟเวอร์ได้รับสิ่งนี้และถอดรหัสหนึ่งครั้ง จะเห็นว่า "my%20file.pdf" เป็นชื่อไฟล์ตามตัวอักษร แทนที่จะรับรู้ว่าเป็น "my file.pdf" แอปพลิเคชันใดๆ ที่คาดว่าจะได้รับเพียงการถอดรหัสเพียงครั้งเดียวจะได้รับผลลัพธ์ที่เสียหาย ที่แย่กว่านั้นคือ นักพัฒนาที่ถอดรหัสสองครั้งเพื่อแก้ไขปัญหาเกี่ยวกับค่าที่ถูกเข้ารหัสเพียงครั้งเดียว จะทำให้ข้อมูลที่ถูกต้องเสียหายด้วยรหัสผ่านการถอดรหัสเพิ่มเติม
ตัวอย่างการทำงาน: ถอดรหัส URL ที่เข้ารหัสสองเท่าทีละครั้ง - แต่ละรหัสผ่านเปิดเผยอะไรและเมื่อใดที่ควรหยุด
รหัส JavaScript ฝั่งไคลเอ็นต์และค่าเริ่มต้นของเฟรมเวิร์กฝั่งเซิร์ฟเวอร์เป็นสาเหตุที่พบบ่อยที่สุดของการเข้ารหัสซ้ำโดยไม่ตั้งใจในระบบที่ใช้งานจริง แอปพลิเคชัน JavaScript อาจใช้ encodeURIComponent กับค่า จากนั้นส่งผ่านโดยตรงไปยังเฟรมเวิร์กที่เข้ารหัสเอาต์พุตสตริงทั้งหมดตามค่าเริ่มต้น ดังนั้นจึงเข้ารหัสเครื่องหมายเปอร์เซ็นต์เป็นครั้งที่สอง เลเยอร์พร็อกซีย้อนกลับที่มีไว้เพื่อฆ่าเชื้อ URL อาจเข้ารหัสพารามิเตอร์ที่เข้ารหัสไว้ล่วงหน้าจากแอปพลิเคชันแบ็กเอนด์อีกครั้ง
การเปลี่ยนเส้นทาง URL ที่สร้างขึ้นโดยการเชื่อมอินพุตที่ผู้ใช้ระบุเข้ากับฟังก์ชันตัวช่วยเฟรมเวิร์กสามารถเข้ารหัสทั้งสองขั้นตอนพร้อมกันได้ ตัวอย่างการทำงาน: ผู้ใช้ส่ง "test&value" ผ่านแบบฟอร์ม HTML เบราว์เซอร์จะเข้ารหัสเป็น "test%26value" กรอบงานจะเห็นข้อความเปอร์เซ็นต์ตามตัวอักษรและเข้ารหัส ทำให้เกิด "test%2526value" ตัวถอดรหัสตัวหนึ่งให้ "test%26value" แต่ก็ยังผิดอยู่
เมื่อจงใจเข้ารหัสสองครั้ง — URL ดำเนินการภายในพารามิเตอร์การค้นหาของ URL อื่น
การเข้ารหัสสองครั้งโดยเจตนานั้นใช้ได้ในกรณีเฉพาะกรณีหนึ่ง: เมื่อ URL ต้องเคลื่อนที่ภายในพารามิเตอร์การสืบค้นของ URL อื่น บางครั้งกระแส OAuth และลิงก์ส่งคืนการเข้าสู่ระบบจำเป็นต้องซ้อนอันหนึ่งที่สมบูรณ์ URL ไว้ในอีกอันหนึ่ง URL ภายในจะต้องเข้ารหัสเปอร์เซ็นต์อย่างสมบูรณ์ก่อน จากนั้นสตริงที่เข้ารหัสทั้งหมดจะต้องถูกเข้ารหัสอีกครั้งเป็นค่าพารามิเตอร์สำหรับ URL ภายนอก
การเข้ารหัสสองครั้งนี้เป็นการกระทำโดยเจตนาและจำเป็นอย่างยิ่งในกรณีเหล่านี้ ตัวแยกวิเคราะห์พารามิเตอร์ภายนอกจะถอดรหัสหนึ่งครั้ง โดยให้ค่าภายในที่เข้ารหัสยังคง URL จากนั้นระบบภายในจะถอดรหัสอีกครั้ง โดยกู้คืน URL ดั้งเดิม กุญแจสำคัญคือการทำความเข้าใจเจตนาและบันทึกไว้อย่างชัดเจนในความคิดเห็นของโค้ดสำหรับผู้ดูแลในอนาคต
ข้อผิดพลาดทั่วไป — การถอดรหัสจนกระทั่งไม่มีอะไรเปลี่ยนแปลง ซึ่งจะทำให้ค่าที่มี %25 ถูกต้องตามกฎหมายเสียหาย
ข้อผิดพลาดคลาสสิกและอันตรายคือการถอดรหัสซ้ำๆ จนกระทั่งไม่มีอะไรเปลี่ยนแปลง ซึ่งจะทำให้ค่าที่มีเครื่องหมายเปอร์เซ็นต์ในข้อมูลจริงเสียหาย พารามิเตอร์เช่น "ส่วนลด%2525" (แทนตัวอักษร "%25" ที่เข้ารหัสเป็นค่าพารามิเตอร์ จากนั้นเข้ารหัสอีกครั้งสำหรับการขนส่ง) ถูกต้องโดยสมบูรณ์จากการออกแบบ การถอดรหัสครั้งเดียวจะได้ "ส่วนลด%25" ซึ่งยังคงถูกต้อง การถอดรหัสครั้งที่สองจะทำให้มี "ส่วนลด%" ซึ่งไม่ถูกต้องและทำให้ข้อมูลสูญหาย
นักพัฒนาซอฟต์แวร์อาจถือว่า "%25" เป็นข้อผิดพลาดและถอดรหัสซ้ำๆ ทำให้สูญเสียเครื่องหมายเปอร์เซ็นต์ ให้ถอดรหัสหลาย ๆ ครั้งตามที่สถาปัตยกรรมของคุณต้องการ: หนึ่งครั้งสำหรับพารามิเตอร์, ซ้อนกันสองครั้ง นับเลเยอร์เพื่อทราบการดำเนินการถอดรหัสที่ถูกต้อง
สิ่งนี้ไม่ครอบคลุมถึง — HTML การเข้ารหัสเอนทิตีที่เลเยอร์อยู่ด้านบนของ URL ซึ่ง HTML เอนทิตี Escaper จัดการ
ข้อผิดพลาดทั่วไป ได้แก่ การเข้ารหัส URL ทั้งหมดด้วย encodeURIComponent จากนั้นคาดหวังว่าเครื่องหมายทับและโคลอนจะทำงานเป็นตัวคั่นโครงสร้าง ซึ่งจะไม่สามารถทำได้หลังจากการเข้ารหัส ข้อผิดพลาดที่พบบ่อยอีกประการหนึ่งคือการผสมผสานมาตรฐานการเข้ารหัสที่แตกต่างกัน: โค้ดบางตัวใช้การเข้ารหัสเปอร์เซ็นต์ต่อ RFC 3986 และโค้ดอื่น ๆ ใช้การเข้ารหัสแบบฟอร์มโดยมีเครื่องหมายบวกแทนช่องว่าง ค่าเช่น "my+file" มีความคลุมเครืออย่างแท้จริง อาจหมายถึง "ไฟล์ของฉัน" หรืออาจหมายถึงข้อความตามตัวอักษร "my+file" ที่มีเครื่องหมายบวก
หากการเข้ารหัสเปอร์เซ็นต์แตะ "my+file" ก่อน มันจะกลายเป็น "my%2Bfile" หากการถอดรหัสแบบฟอร์มตามมา โดยคาดว่าจะมีเครื่องหมายบวกเท่ากับช่องว่าง แสดงว่ายังคงผิดอยู่ ความสม่ำเสมอของเลเยอร์เป็นสิ่งสำคัญ ทุกระบบต้องใช้มาตรฐานการเข้ารหัสเดียวกัน หรือแต่ละเลเยอร์จะต้องมีการบันทึกไว้อย่างชัดเจน
ประเด็นสำคัญ: เข้ารหัสหนึ่งครั้งต่อเลเยอร์ — วิธีที่ตัวเข้ารหัสและตัวถอดรหัส URL ให้คุณถอดรหัสทีละครั้งและดูผลลัพธ์ระดับกลางแต่ละรายการ
เมื่อคุณระบุการเข้ารหัสสองครั้งที่เกิดขึ้นในระบบที่ใช้งานจริงได้สำเร็จ การแก้ไขจะขึ้นอยู่กับตำแหน่งที่เกิดการทำซ้ำในไปป์ไลน์ หากทั้งโค้ดไคลเอ็นต์และเฟรมเวิร์กกำลังเข้ารหัส ให้ลบการเข้ารหัสออกจากหนึ่งในนั้นโดยสมบูรณ์ หากพารามิเตอร์เดินทางผ่านบริการแบ็กเอนด์หลายบริการ ให้ติดตามเส้นทางที่สมบูรณ์ผ่านแต่ละบริการ และค้นหาบริการที่มีการเข้ารหัสในเวลาที่ไม่ควรทำเช่นนั้น
ทดสอบการแก้ไขอย่างละเอียดโดยส่งข้อมูลตัวอย่างผ่านไปป์ไลน์ตั้งแต่ต้นทางถึงปลายทางที่สมบูรณ์ และตรวจสอบว่าข้อมูลมาถึงที่ปลายทางโดยไม่มีการเปลี่ยนแปลงโดยสิ้นเชิง บันทึกสมมติฐานการเข้ารหัสที่แต่ละขอบเขตอย่างชัดเจน: "จุดสิ้นสุดนี้ส่งคืนพารามิเตอร์ที่เข้ารหัสเป็นเปอร์เซ็นต์" หรือ "มิดเดิลแวร์นี้คาดว่าจะได้รับข้อมูลดิบ UTF-8 และใช้การเข้ารหัสกับจุดนั้น" รวมจำนวนการถอดรหัสที่คาดหวังไว้ในเอกสารประกอบสำหรับนักพัฒนาในอนาคต