วิธีการทำงานของ HTML entity encoding
HTML entity คือการอ้างอิงอักขระที่เบราว์เซอร์แยกวิเคราะห์กลับเป็นอักขระเดียว อักขระสงวน HTML ห้าตัว (<, >, &, ", ') ต้องถูกเข้ารหัสเสมอเมื่อข้อความแสดงผลเป็น HTML ส่วนที่เหลือเป็นทางเลือกขึ้นอยู่กับการเข้ารหัสเอกสาร
- เลือกโหมดและขอบเขต. โหมดเข้ารหัสจะประมวลผลอักขระละตัวในข้อมูลนำเข้า โหมดถอดรหัสจะสแกนหารูปแบบ entity ตัวสลับขอบเขตกำหนดว่าจะเข้ารหัสเฉพาะห้าอักขระ HTML-safe หรือรวมทุก code point ที่ไม่ใช่ ASCII ด้วย
- เลือกรูปแบบ entity. Named entity (
©) อ่านง่ายในซอร์สโค้ด การอ้างอิง decimal (©) และ hex (©) รองรับทุก Unicode code point โดยไม่ต้องมีชื่อ อีเมลไคลเอนต์รุ่นเก่าและ XML parser นิยมรูปแบบตัวเลข - ประมวลผลข้อมูลนำเข้า. ในการเข้ารหัส จะอ่านแต่ละ code point และค้นหาในตารางประมาณ 200 named entity ที่พบบ่อย กรณีไม่พบจะใช้รูปแบบตัวเลขแทน ในการถอดรหัส จะสแกนด้วย regex เดียวที่จับคู่
&name;,&#NNN;และ&#xHH;ในการผ่านครั้งเดียว - จับคู่กับอักขระ. การจับคู่ named จะแก้ไขผ่านตารางย้อนกลับ การจับคู่ตัวเลขจะผ่าน
String.fromCodePointด้วยฐาน 10 หรือฐาน 16 named entity ที่ไม่รู้จักจะถูกเว้นไว้ไม่เปลี่ยนแปลงเพื่อให้ข้อมูลนำเข้าบางส่วนสามารถแปลงกลับไปกลับมาได้โดยไม่สูญเสียข้อมูล - โหมดสด. เปิดโหมดสดแล้วทุกการพิมพ์จะทำการแปลงซ้ำด้วย debounce 150 มิลลิวินาที มีประโยชน์เมื่อคุณกำลังปรับแต่ง snippet และต้องการผลตอบรับทันทีก่อนวางลงในเทมเพลต
ทำไมต้องเข้ารหัส HTML entity
- ป้องกันข้อมูลผู้ใช้ไม่ให้ทำลายเลย์เอาต์. เมื่อผู้ใช้พิมพ์
<ลงในช่องความคิดเห็น การนำข้อความนั้นไปใส่ใน HTML โดยตรงจะเขียนทับส่วนที่เหลือของหน้า การเข้ารหัสอักขระสงวนก่อนทำให้เบราว์เซอร์แสดงอักขระแทนที่จะแยกวิเคราะห์เป็นเริ่มต้น tag - รักษาค่า attribute ให้ถูกต้อง. การฝังสตริงที่มีเครื่องหมายคำพูดใน HTML attribute ต้องแทนที่เครื่องหมายคำพูดที่ฝังด้วย
"(สำหรับ attr ที่ใช้เครื่องหมายคู่) หรือ'(สำหรับที่ใช้เครื่องหมายเดี่ยว) มิฉะนั้น parser จะปิด attribute เร็วเกินไปและส่วนที่เหลือของบรรทัดจะกลายเป็น markup ที่หลงเหลือ - ทำให้ HTML ที่ไม่ตั้งใจในข้อมูลที่จัดเก็บไม่เป็นอันตราย. บันทึก รายงานข้อผิดพลาด และการส่งออกแชทมักมีวงเล็บมุมและ ampersand จริง การเข้ารหัส entity ก่อนวางลงในหน้าเอกสารจะรักษาสำเนานั้นให้มองเห็นเป็นข้อความแทนที่จะกระตุ้น renderer หรือตัวตรวจจับลิงก์อัตโนมัติ
- แชร์ code snippet อย่างปลอดภัย. การโพสต์ tag ตัวอย่างเช่น
<script>alert(1)</script>ในบล็อก อีเมล หรือ Slack ต้องเข้ารหัสวงเล็บเพื่อให้ snippet แสดงแทนที่จะทำงาน เทคนิคเดียวกันนี้ครอบคลุม RSS feed body และฟิลด์ `description` ของ JSON-LD
การใช้งานทั่วไป
การเข้ารหัส entity ปรากฏทุกที่ที่ข้อความดิบถูกประกอบเข้ากับ HTML ระหว่างรันไทม์ — แม้เมื่อ framework มักจัดการให้คุณ เครื่องมือ manual ก็ยังมีประโยชน์ในช่วงเวลาที่ไม่ทำ
- เทมเพลต server-rendered: Jinja2, ERB, Twig และ Handlebars escape อัตโนมัติโดยค่าเริ่มต้น แต่ raw block และตัวทำเครื่องหมาย `safe` จะปิดสิ่งนั้น — codec ช่วยให้คุณยืนยันสิ่งที่ escape จะสร้างขึ้น
- การสร้างอีเมลและจดหมายข่าว: เครื่องยนต์เทมเพลต ESP หลายตัวไม่ auto-escape merge field ดังนั้น smart quote และเครื่องหมายลิขสิทธิ์ในชื่อที่ผู้ใช้ระบุต้องเข้ารหัสล่วงหน้า
- เอกสารและตัวอย่างโค้ด: การวาง HTML tag ตัวอย่างลงในบล็อก Markdown หรือ snippet ของ static site ต้องเข้ารหัสวงเล็บเพื่อให้ renderer ถือว่าเป็นข้อความที่มองเห็นได้
ตัวอย่างที่ทำงานได้จริง
วาง <script>alert('hi')</script> ในข้อมูลนำเข้าโดยตั้งโหมดเป็น Encode, รูปแบบ Named, ขอบเขต Minimal ผลลัพธ์อ่านว่า <script>alert('hi')</script> เปลี่ยนรูปแบบเป็น Numeric hex ข้อมูลนำเข้าเดิมจะสร้าง <script>alert('hi')</script> พลิกโหมดเป็น Decode วางสตริงที่เข้ารหัสกลับเข้าไป แล้ว tag ต้นฉบับจะกลับมาครบถ้วน
FAQ
HTML entity คืออะไร?
HTML entity คือการอ้างอิงอักขระที่เบราว์เซอร์แทนที่กลับเป็นอักขระเดียวเมื่อแยกวิเคราะห์หน้า มีสามรูปแบบ: named (เช่น & สำหรับ &), decimal numeric (&) และ hex numeric (&) อักขระสงวน HTML ห้าตัว (<, >, &, ", ') ต้องถูกเข้ารหัสทุกครั้งที่ข้อความถูกนำไปไว้ใน HTML named entity ที่มีชื่ออีกประมาณ 2,225 รายการครอบคลุมสัญลักษณ์ สำเนียง และตัวอักษรกรีก แต่เป็นทางเลือกเมื่อการเข้ารหัสเอกสารเป็น UTF-8
ควรใช้ named หรือ numeric entity เมื่อใด?
ใช้ named entity เมื่อต้องการให้ซอร์สอ่านง่าย (มนุษย์ที่ตรวจสอบ © ในเทมเพลตเข้าใจทันที) ใช้ numeric (decimal หรือ hex) เมื่อผู้บริโภคเป็นรุ่นเก่าหรือเข้มงวดกว่า — XML parser, อีเมลไคลเอนต์รุ่นเก่า และ feed reader บางตัวรู้จักเฉพาะ named entity HTML5 ชุดย่อยเล็กน้อย และทั้งหมดรู้จักรูปแบบตัวเลข Hex มักชนะในบริบทที่เน้นความปลอดภัยเพราะตรงกับ Unicode code-point notation ที่ใช้ในเอกสาร spec
การถอดรหัสรองรับ hex entity เช่น & หรือไม่?
ใช่ ตัวถอดรหัสใช้ regex เดียวที่จับคู่สามรูปแบบ entity ในการผ่านครั้งเดียว: &name;, &#NNN; และ &#xHH; การจับคู่ตัวเลขจะแก้ไขด้วย String.fromCodePoint ใช้ฐาน 10 หรือฐาน 16 ข้อมูลผสม (named และ numeric ในสตริงเดียวกัน) ถอดรหัสได้ถูกต้อง และชื่อที่ไม่รู้จักจะถูกเว้นไว้เป็นข้อความตามตัวอักษรเพื่อให้ข้อมูลนำเข้าบางส่วนแปลงกลับไปกลับมาได้โดยไม่สูญเสีย
ปลอดภัยที่จะใช้กับข้อมูลที่ไม่น่าเชื่อถือหรือไม่?
ตัวแปลงเองทำงานในเบราว์เซอร์เท่านั้นและไม่ส่งข้อมูลของคุณไปที่ใด ความปลอดภัยของผลลัพธ์ที่จะฝังขึ้นอยู่กับบริบท การเข้ารหัส entity จัดการบริบท HTML body และค่า attribute ซึ่งครอบคลุมกรณี OWASP Rule #1 บริบท JavaScript (inline event handler, block `<script>`), CSS และ URL แต่ละอย่างต้องการกฎการเข้ารหัสของตัวเอง — การเข้ารหัส entity เพียงอย่างเดียวไม่เพียงพอ สำหรับการป้องกันเชิงลึกฝั่งเซิร์ฟเวอร์ ให้จับคู่กับ template engine ที่รู้บริบทเช่น DOMPurify หรือ auto-escape ของ framework ของคุณ
การเข้ารหัส entity ฝั่งเบราว์เซอร์อยู่ที่ขอบเขตระหว่างข้อมูลผู้ใช้และ HTML ที่แสดงผล การแปลงในเครื่องหมายความคุณสามารถตรวจสอบสิ่งที่ framework ของคุณจะส่งออกได้ โดยไม่ต้องส่งข้อความต้นฉบับไปยังเครื่องมือของบุคคลที่สาม