Unescape HTML เอนทิตีใน Javascript?


177

ฉันมีรหัสจาวาสคริปต์ที่สื่อสารกับแบ็กเอนด์ XML-RPC XML-RPC ส่งคืนสตริงของฟอร์ม:

<img src='myimage.jpg'>

อย่างไรก็ตามเมื่อฉันใช้ Javascript เพื่อแทรกสตริงลงใน HTML พวกเขาแสดงผลอย่างแท้จริง ฉันไม่เห็นภาพฉันเห็นสตริง:

<img src='myimage.jpg'>

ฉันเดาว่า HTML กำลังถูกหลบหนีผ่านช่องทาง XML-RPC

ฉันจะยกเลิกการซ่อนสตริงใน Javascript ได้อย่างไร ฉันลองใช้เทคนิคต่าง ๆ ในหน้านี้ไม่สำเร็จ: http://paulschreiber.com/blog/2008/09/20/javascript-how-to-unescape-html-entities/

วิธีอื่นในการวินิจฉัยปัญหามีอะไรบ้าง


1
ลองทำดังนี้: stackoverflow.com/questions/4480757/…
XP1

คำตอบ:


177

แก้ไข:คุณควรใช้ DOMParser API เนื่องจากWladimir แนะนำให้ฉันแก้ไขคำตอบก่อนหน้าของฉันเนื่องจากฟังก์ชั่นที่โพสต์นั้นมีช่องโหว่ด้านความปลอดภัย

ตัวอย่างต่อไปนี้เป็นรหัสของคำตอบเก่าที่มีการดัดแปลงเล็กน้อย: การใช้textareaแทนการdivลดช่องโหว่ XSS แต่ก็ยังคงเป็นปัญหาใน IE9 และ Firefox

function htmlDecode(input){
  var e = document.createElement('textarea');
  e.innerHTML = input;
  // handle case of empty input
  return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue;
}

htmlDecode("&lt;img src='myimage.jpg'&gt;"); 
// returns "<img src='myimage.jpg'>"

โดยทั่วไปฉันสร้างองค์ประกอบ DOM โดยทางโปรแกรมกำหนด HTML ที่เข้ารหัสไปยัง innerHTML และดึงข้อมูล nodeValue จากโหนดข้อความที่สร้างในการแทรก InnerHTML เนื่องจากเพิ่งสร้างองค์ประกอบ แต่ไม่เคยเพิ่มองค์ประกอบจึงไม่มีการแก้ไข HTML ของไซต์

มันจะทำงานข้ามเบราว์เซอร์ (รวมถึงเบราว์เซอร์ที่เก่ากว่า) และยอมรับเอนทิตีอักขระ HTMLทั้งหมด

แก้ไข: รหัสเก่าของรุ่นนี้ไม่ได้ทำงานบน IE ที่มีอินพุตว่างตามหลักฐานที่นี่ใน jsFiddle (ดูใน IE) เวอร์ชันด้านบนใช้งานได้กับอินพุตทั้งหมด

UPDATE: ปรากฏว่าสิ่งนี้ใช้ไม่ได้กับสตริงจำนวนมากและยังมีช่องโหว่ด้านความปลอดภัยอีกด้วยดูความคิดเห็น


เข้าใจแล้วคุณเปลี่ยนเป็น 'ดังนั้นขอให้ฉันลบความคิดเห็นของฉันกลับมาขอบคุณมันใช้งานได้ดี +1
คุณ

1
@ S.Mark: &apos;ไม่ได้เป็นของ HTML 4 Entities นั่นคือสาเหตุ! w3.org/TR/html4/sgml/entities.html fishbowl.pastiche.org/2003/07/01/the_curse_of_apos
CMS

2
ดูหมายเหตุของ @ kender เกี่ยวกับความปลอดภัยที่ไม่ดีของวิธีการนี้
โจเซฟ Turian

2
ดูบันทึกของฉันไป @kender เกี่ยวกับการทดสอบที่น่าสงสารที่เขาทำ;)
Roatin Marth

24
ฟังก์ชันนี้เป็นอันตรายด้านความปลอดภัยรหัส JavaScript จะทำงานแม้จะไม่ได้เพิ่มองค์ประกอบลงใน DOM ดังนั้นนี่คือสิ่งที่จะใช้เฉพาะถ้าสายอักขระเข้าเชื่อถือได้ ฉันเพิ่มคำตอบของฉันเองเพื่ออธิบายปัญหาและเสนอวิธีแก้ปัญหาที่ปลอดภัย ผลข้างเคียงจะไม่ถูกตัดออกหากมีหลายโหนดข้อความ
Wladimir Palant

375

คำตอบส่วนใหญ่ให้ที่นี่มีข้อเสียใหญ่: ถ้าสตริงที่คุณกำลังพยายามที่จะแปลงไม่น่าเชื่อถือแล้วคุณจะจบลงด้วยการข้าม Site Scripting (XSS) ช่องโหว่ สำหรับฟังก์ชันในคำตอบที่ยอมรับให้พิจารณาสิ่งต่อไปนี้:

htmlDecode("<img src='dummy' onerror='alert(/xss/)'>");

สตริงที่นี่มีแท็ก HTML ที่ไม่ใช้ค่า Escape ดังนั้นแทนที่จะถอดรหัสสิ่งใดhtmlDecodeฟังก์ชันจะใช้งานโค้ด JavaScript ที่ระบุในสตริง

สิ่งนี้สามารถหลีกเลี่ยงได้โดยใช้DOMParserซึ่งรองรับในเบราว์เซอร์สมัยใหม่ทั้งหมด :

function htmlDecode(input) {
  var doc = new DOMParser().parseFromString(input, "text/html");
  return doc.documentElement.textContent;
}

console.log(  htmlDecode("&lt;img src='myimage.jpg'&gt;")  )    
// "<img src='myimage.jpg'>"

console.log(  htmlDecode("<img src='dummy' onerror='alert(/xss/)'>")  )  
// ""

ฟังก์ชั่นนี้รับประกันว่าจะไม่เรียกใช้โค้ด JavaScript ใด ๆ ว่าเป็นผลข้างเคียง แท็ก HTML ใด ๆ จะถูกละเว้นเฉพาะเนื้อหาข้อความเท่านั้นที่จะถูกส่งคืน

หมายเหตุความเข้ากันได้ : การแยก HTML ด้วยDOMParserอย่างน้อยต้องเป็น Chrome 30, Firefox 12, Opera 17, Internet Explorer 10, Safari 7.1 หรือ Microsoft Edge ดังนั้นเบราว์เซอร์ทั้งหมดที่ไม่มีการสนับสนุนจะผ่าน EOL และในปี 2560 มีเพียงเบราว์เซอร์รุ่นล่าสุดที่ยังคงสามารถพบเห็นได้ในบางครั้งเท่านั้นคือ Internet Explorer และ Safari เวอร์ชันเก่า


19
ฉันคิดว่าคำตอบนี้ดีที่สุดเพราะพูดถึงช่องโหว่ XSS
КонстантинВан

2
โปรดทราบว่า (ตามการอ้างอิงของคุณ) DOMParserไม่สนับสนุน"text/html"ก่อน Firefox 12.0 และยังมีบางรุ่นล่าสุดของเบราว์เซอร์ที่ไม่ได้รับการสนับสนุน DOMParser.prototype.parseFromString()ตามการอ้างอิงของคุณDOMParserยังคงเป็นเทคโนโลยีทดลองและสแตนอินใช้innerHTMLคุณสมบัติซึ่งตามที่คุณชี้ให้เห็นในการตอบสนองต่อวิธีการของฉันมีช่องโหว่ XSS นี้ (ซึ่งควรได้รับการแก้ไขโดยผู้ขายเบราว์เซอร์)
SharpEars

4
@PointedEars: ใครสนใจ Firefox 12 ในปี 2559? สิ่งที่มีปัญหาคือ Internet Explorer สูงถึง 9.0 และ Safari สูงสุด 7.0 หากใครไม่สามารถสนับสนุนพวกเขา (ซึ่งหวังว่าจะเป็นทุกคนในไม่ช้า) DOMParser เป็นตัวเลือกที่ดีที่สุด ถ้าไม่ใช่ - ใช่การประมวลผลเอนทิตีจะเป็นตัวเลือกเท่านั้น
Wladimir Palant

4
@PointedEars: <script>แท็กที่ไม่ได้ถูกเรียกใช้งานไม่ใช่กลไกความปลอดภัยกฎนี้เพียง แต่หลีกเลี่ยงปัญหาเรื่องเวลาหากหากการตั้งค่าinnerHTMLสามารถเรียกใช้สคริปต์ซิงโครนัสเป็นผลข้างเคียง การฆ่าเชื้อรหัส HTML เป็นเรื่องที่ยุ่งยากและinnerHTMLไม่เคยลองมาก่อนเพราะหน้าเว็บอาจตั้งใจตั้งค่าตัวจัดการเหตุการณ์แบบอินไลน์ นี่ไม่ใช่กลไกสำหรับข้อมูลที่ไม่ปลอดภัยหยุดแบบสมบูรณ์
Wladimir Palant

1
@ ИльяЗеленько: คุณวางแผนที่จะใช้รหัสนี้ในวงแคบหรือทำไมประสิทธิภาพการทำงานจึงมีความสำคัญ? คำตอบของคุณมีความเสี่ยงต่อ XSS อีกครั้งมันคุ้มหรือไม่
Wladimir Palant

37

หากคุณใช้ jQuery:

function htmlDecode(value){ 
  return $('<div/>').html(value).text(); 
}

มิฉะนั้นให้ใช้Encoder Object ของซอฟต์แวร์อย่างเข้มงวดซึ่งมีhtmlDecode()ฟังก์ชั่นที่ยอดเยี่ยม


59
อย่า (ไม่ซ้ำ) ใช้นี้สำหรับผู้ใช้สร้างเนื้อหาอื่น ๆ กว่าเนื้อหาที่สร้างโดยการนี้ผู้ใช้ หากมีแท็ก <script> ในค่าเนื้อหาของสคริปต์จะถูกดำเนินการ!
Malvolio

ฉันไม่พบใบอนุญาตสำหรับที่ใดก็ได้ในเว็บไซต์ คุณรู้หรือไม่ว่าใบอนุญาตคืออะไร?
TRiG

มีใบอนุญาตในส่วนหัวของแหล่งที่มาคือ GPL
Chris Fulstow

6
ใช่ฟังก์ชั่นนั้นเปิดทางให้กับ XSS: ลอง htmlDecode ("<script> การแจ้งเตือน (12) </script> 123 & gt;")
Dinis Cruz

ความหมายของ$ ('<div />')คืออะไร
Echo Yang

13

เคล็ดลับคือการใช้พลังของเบราว์เซอร์ในการถอดรหัสอักขระ HTML พิเศษ แต่ไม่อนุญาตให้เบราว์เซอร์เรียกใช้ผลลัพธ์ราวกับว่าเป็น html จริง ... ฟังก์ชันนี้ใช้ regex เพื่อระบุและแทนที่อักขระ HTML ที่เข้ารหัสหนึ่งอักขระ ขณะนั้น.

function unescapeHtml(html) {
    var el = document.createElement('div');
    return html.replace(/\&[#0-9a-z]+;/gi, function (enc) {
        el.innerHTML = enc;
        return el.innerText
    });
}

regex สามารถจับคู่กันได้ดีขึ้น/\&#?[0-9a-z]+;/giเนื่องจาก # ควรปรากฏเป็นอักขระตัวที่สองถ้าเลย
TheAtomicOption

นี่คือคำตอบที่ดีที่สุด หลีกเลี่ยงช่องโหว่ XSS และไม่ตัดแท็ก HTML
Emmanuel

6

คำตอบของ CMS ใช้งานได้ดียกเว้นว่า HTML ที่คุณต้องการยกเลิกการใช้ Unescape นั้นยาวมากและยาวกว่า 65536 ตัวอักษร เนื่องจากใน Chrome HTML ภายในจะถูกแบ่งออกเป็นโหนดย่อยหลายโหนดแต่ละโหนดมีความยาวสูงสุด 65536 และคุณต้องเชื่อมต่อกัน ฟังก์ชั่นนี้ใช้งานได้กับสตริงที่ยาวมากด้วย:

function unencodeHtmlContent(escapedHtml) {
  var elem = document.createElement('div');
  elem.innerHTML = escapedHtml;
  var result = '';
  // Chrome splits innerHTML into many child nodes, each one at most 65536.
  // Whereas FF creates just one single huge child node.
  for (var i = 0; i < elem.childNodes.length; ++i) {
    result = result + elem.childNodes[i].nodeValue;
  }
  return result;
}

ดูคำตอบเกี่ยวกับinnerHTMLความยาวสูงสุดสำหรับข้อมูลเพิ่มเติม: https://stackoverflow.com/a/27545633/694469


3

ไม่ใช่การตอบคำถามของคุณโดยตรง แต่มันจะดีกว่าหรือที่ RPC ของคุณจะกลับโครงสร้างบางอย่าง (ไม่ว่าจะเป็น XML หรือ JSON หรืออะไรก็ตาม) ด้วยข้อมูลภาพเหล่านั้น (URL ในตัวอย่างของคุณ) ภายในโครงสร้างนั้น

จากนั้นคุณสามารถแยกวิเคราะห์ในจาวาสคริปต์ของคุณและสร้างการ<img>ใช้จาวาสคริปต์เอง

โครงสร้างที่คุณได้รับจาก RPC อาจมีลักษณะดังนี้:

{"img" : ["myimage.jpg", "myimage2.jpg"]}

ฉันคิดว่าวิธีนี้จะดีกว่าเนื่องจากการฉีดโค้ดที่มาจากแหล่งภายนอกลงในหน้าของคุณนั้นดูไม่ปลอดภัย การถ่ายภาพใครบางคนกำลังแย่งชิงสคริปต์ XML-RPC ของคุณและวางสิ่งที่คุณไม่ต้องการเข้าไป (แม้แต่บางจาวาสคริปต์ ... )


วิธีการ @CMS ด้านบนมีข้อบกพร่องด้านความปลอดภัยนี้หรือไม่
Joseph Turian

ฉันเพิ่งตรวจสอบอาร์กิวเมนต์ต่อไปนี้ที่ส่งไปยัง htmlDecode fuction: htmlDecode ("& lt; img src = 'myimage.jpg' & gt; & lt; สคริปต์ & gt; document.write ('xxxxx'); & lt; / script & gt;") อิลิเมนต์ <script> </script> ที่อาจไม่ดีเลย และฉันยังคิดว่าการคืนโครงสร้างแทนที่จะแทรกข้อความจะดีกว่าคุณสามารถจัดการข้อผิดพลาดได้เป็นอย่างดี
ทำลาย

1
ฉันแค่พยายามhtmlDecode("&lt;img src='myimage.jpg'&gt;&lt;script&gt;alert('xxxxx');&lt;/script&gt;")และไม่มีอะไรเกิดขึ้น ฉันได้สตริง html ที่ถอดรหัสกลับมาตามที่คาดไว้
Roatin Marth

2

คริสคำตอบที่เป็นสิ่งที่ดีและสง่างาม แต่ก็ล้มเหลวถ้าค่าไม่ได้กำหนด การปรับปรุงที่เรียบง่ายทำให้มันแข็งแกร่ง:

function htmlDecode(value) {
   return (typeof value === 'undefined') ? '' : $('<div/>').html(value).text();
}

หากปรับปรุงให้ทำดังนี้:return (typeof value !== 'string') ? '' : $('<div/>').html(value).text();
SynCap

2

ยินดีต้อนรับคุณ ... แค่ผู้ส่งสาร ... เครดิตทั้งหมดไปที่ ourcodeworld.com ลิงค์ด้านล่าง

window.htmlentities = {
        /**
         * Converts a string to its html characters completely.
         *
         * @param {String} str String with unescaped HTML characters
         **/
        encode : function(str) {
            var buf = [];

            for (var i=str.length-1;i>=0;i--) {
                buf.unshift(['&#', str[i].charCodeAt(), ';'].join(''));
            }

            return buf.join('');
        },
        /**
         * Converts an html characterSet into its original character.
         *
         * @param {String} str htmlSet entities
         **/
        decode : function(str) {
            return str.replace(/&#(\d+);/g, function(match, dec) {
                return String.fromCharCode(dec);
            });
        }
    };

เครดิตทั้งหมด: https://ourcodeworld.com/articles/read/188/encode-and-decode-html-entities-using-pure-javascript


2

นี่เป็นโซลูชันที่ครอบคลุมที่สุดที่ฉันได้ลองมา:

const STANDARD_HTML_ENTITIES = {
    nbsp: String.fromCharCode(160),
    amp: "&",
    quot: '"',
    lt: "<",
    gt: ">"
};

const replaceHtmlEntities = plainTextString => {
    return plainTextString
        .replace(/&#(\d+);/g, (match, dec) => String.fromCharCode(dec))
        .replace(
            /&(nbsp|amp|quot|lt|gt);/g,
            (a, b) => STANDARD_HTML_ENTITIES[b]
        );
};

"ครอบคลุมมากที่สุด"? คุณได้ลองใช้กับชุดทดสอบที่ครอบคลุมจริงหรือไม่?
Dan Dascalescu

1

ฉันคลั่งไคล้มากพอที่จะผ่านและทำให้ฟังก์ชั่นนี้น่าจะดีถ้าไม่ครบถ้วนสมบูรณ์:

function removeEncoding(string) {
    return string.replace(/&Agrave;/g, "À").replace(/&Aacute;/g, "Á").replace(/&Acirc;/g, "Â").replace(/&Atilde;/g, "Ã").replace(/&Auml;/g, "Ä").replace(/&Aring;/g, "Å").replace(/&agrave;/g, "à").replace(/&acirc;/g, "â").replace(/&atilde;/g, "ã").replace(/&auml;/g, "ä").replace(/&aring;/g, "å").replace(/&AElig;/g, "Æ").replace(/&aelig;/g, "æ").replace(/&szlig;/g, "ß").replace(/&Ccedil;/g, "Ç").replace(/&ccedil;/g, "ç").replace(/&Egrave;/g, "È").replace(/&Eacute;/g, "É").replace(/&Ecirc;/g, "Ê").replace(/&Euml;/g, "Ë").replace(/&egrave;/g, "è").replace(/&eacute;/g, "é").replace(/&ecirc;/g, "ê").replace(/&euml;/g, "ë").replace(/&#131;/g, "ƒ").replace(/&Igrave;/g, "Ì").replace(/&Iacute;/g, "Í").replace(/&Icirc;/g, "Î").replace(/&Iuml;/g, "Ï").replace(/&igrave;/g, "ì").replace(/&iacute;/g, "í").replace(/&icirc;/g, "î").replace(/&iuml;/g, "ï").replace(/&Ntilde;/g, "Ñ").replace(/&ntilde;/g, "ñ").replace(/&Ograve;/g, "Ò").replace(/&Oacute;/g, "Ó").replace(/&Ocirc;/g, "Ô").replace(/&Otilde;/g, "Õ").replace(/&Ouml;/g, "Ö").replace(/&ograve;/g, "ò").replace(/&oacute;/g, "ó").replace(/&ocirc;/g, "ô").replace(/&otilde;/g, "õ").replace(/&ouml;/g, "ö").replace(/&Oslash;/g, "Ø").replace(/&oslash;/g, "ø").replace(/&#140;/g, "Œ").replace(/&#156;/g, "œ").replace(/&#138;/g, "Š").replace(/&#154;/g, "š").replace(/&Ugrave;/g, "Ù").replace(/&Uacute;/g, "Ú").replace(/&Ucirc;/g, "Û").replace(/&Uuml;/g, "Ü").replace(/&ugrave;/g, "ù").replace(/&uacute;/g, "ú").replace(/&ucirc;/g, "û").replace(/&uuml;/g, "ü").replace(/&#181;/g, "µ").replace(/&#215;/g, "×").replace(/&Yacute;/g, "Ý").replace(/&#159;/g, "Ÿ").replace(/&yacute;/g, "ý").replace(/&yuml;/g, "ÿ").replace(/&#176;/g, "°").replace(/&#134;/g, "†").replace(/&#135;/g, "‡").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&#177;/g, "±").replace(/&#171;/g, "«").replace(/&#187;/g, "»").replace(/&#191;/g, "¿").replace(/&#161;/g, "¡").replace(/&#183;/g, "·").replace(/&#149;/g, "•").replace(/&#153;/g, "™").replace(/&copy;/g, "©").replace(/&reg;/g, "®").replace(/&#167;/g, "§").replace(/&#182;/g, "¶").replace(/&Alpha;/g, "Α").replace(/&Beta;/g, "Β").replace(/&Gamma;/g, "Γ").replace(/&Delta;/g, "Δ").replace(/&Epsilon;/g, "Ε").replace(/&Zeta;/g, "Ζ").replace(/&Eta;/g, "Η").replace(/&Theta;/g, "Θ").replace(/&Iota;/g, "Ι").replace(/&Kappa;/g, "Κ").replace(/&Lambda;/g, "Λ").replace(/&Mu;/g, "Μ").replace(/&Nu;/g, "Ν").replace(/&Xi;/g, "Ξ").replace(/&Omicron;/g, "Ο").replace(/&Pi;/g, "Π").replace(/&Rho;/g, "Ρ").replace(/&Sigma;/g, "Σ").replace(/&Tau;/g, "Τ").replace(/&Upsilon;/g, "Υ").replace(/&Phi;/g, "Φ").replace(/&Chi;/g, "Χ").replace(/&Psi;/g, "Ψ").replace(/&Omega;/g, "Ω").replace(/&alpha;/g, "α").replace(/&beta;/g, "β").replace(/&gamma;/g, "γ").replace(/&delta;/g, "δ").replace(/&epsilon;/g, "ε").replace(/&zeta;/g, "ζ").replace(/&eta;/g, "η").replace(/&theta;/g, "θ").replace(/&iota;/g, "ι").replace(/&kappa;/g, "κ").replace(/&lambda;/g, "λ").replace(/&mu;/g, "μ").replace(/&nu;/g, "ν").replace(/&xi;/g, "ξ").replace(/&omicron;/g, "ο").replace(/&piρ;/g, "ρ").replace(/&rho;/g, "ς").replace(/&sigmaf;/g, "ς").replace(/&sigma;/g, "σ").replace(/&tau;/g, "τ").replace(/&phi;/g, "φ").replace(/&chi;/g, "χ").replace(/&psi;/g, "ψ").replace(/&omega;/g, "ω").replace(/&bull;/g, "•").replace(/&hellip;/g, "…").replace(/&prime;/g, "′").replace(/&Prime;/g, "″").replace(/&oline;/g, "‾").replace(/&frasl;/g, "⁄").replace(/&weierp;/g, "℘").replace(/&image;/g, "ℑ").replace(/&real;/g, "ℜ").replace(/&trade;/g, "™").replace(/&alefsym;/g, "ℵ").replace(/&larr;/g, "←").replace(/&uarr;/g, "↑").replace(/&rarr;/g, "→").replace(/&darr;/g, "↓").replace(/&barr;/g, "↔").replace(/&crarr;/g, "↵").replace(/&lArr;/g, "⇐").replace(/&uArr;/g, "⇑").replace(/&rArr;/g, "⇒").replace(/&dArr;/g, "⇓").replace(/&hArr;/g, "⇔").replace(/&forall;/g, "∀").replace(/&part;/g, "∂").replace(/&exist;/g, "∃").replace(/&empty;/g, "∅").replace(/&nabla;/g, "∇").replace(/&isin;/g, "∈").replace(/&notin;/g, "∉").replace(/&ni;/g, "∋").replace(/&prod;/g, "∏").replace(/&sum;/g, "∑").replace(/&minus;/g, "−").replace(/&lowast;/g, "∗").replace(/&radic;/g, "√").replace(/&prop;/g, "∝").replace(/&infin;/g, "∞").replace(/&OEig;/g, "Œ").replace(/&oelig;/g, "œ").replace(/&Yuml;/g, "Ÿ").replace(/&spades;/g, "♠").replace(/&clubs;/g, "♣").replace(/&hearts;/g, "♥").replace(/&diams;/g, "♦").replace(/&thetasym;/g, "ϑ").replace(/&upsih;/g, "ϒ").replace(/&piv;/g, "ϖ").replace(/&Scaron;/g, "Š").replace(/&scaron;/g, "š").replace(/&ang;/g, "∠").replace(/&and;/g, "∧").replace(/&or;/g, "∨").replace(/&cap;/g, "∩").replace(/&cup;/g, "∪").replace(/&int;/g, "∫").replace(/&there4;/g, "∴").replace(/&sim;/g, "∼").replace(/&cong;/g, "≅").replace(/&asymp;/g, "≈").replace(/&ne;/g, "≠").replace(/&equiv;/g, "≡").replace(/&le;/g, "≤").replace(/&ge;/g, "≥").replace(/&sub;/g, "⊂").replace(/&sup;/g, "⊃").replace(/&nsub;/g, "⊄").replace(/&sube;/g, "⊆").replace(/&supe;/g, "⊇").replace(/&oplus;/g, "⊕").replace(/&otimes;/g, "⊗").replace(/&perp;/g, "⊥").replace(/&sdot;/g, "⋅").replace(/&lcell;/g, "⌈").replace(/&rcell;/g, "⌉").replace(/&lfloor;/g, "⌊").replace(/&rfloor;/g, "⌋").replace(/&lang;/g, "⟨").replace(/&rang;/g, "⟩").replace(/&loz;/g, "◊").replace(/&#039;/g, "'").replace(/&amp;/g, "&").replace(/&quot;/g, "\"");
}

ใช้อย่างนั้น:

let decodedText = removeEncoding("Ich hei&szlig;e David");
console.log(decodedText);

พิมพ์: Ich Heiße David

ป.ล. นี้ใช้เวลาทำชั่วโมงครึ่ง


0

ในการ unescape HTML entity * ใน JavaScript คุณสามารถใช้ไลบรารี่ขนาดเล็กhtml-escaper :npm install html-escaper

import {unescape} from 'html-escaper';

unescape('escaped string');

หรือunescapeฟังก์ชั่นจากLodashหรือUnderscoreหากคุณใช้งาน


*) โปรดทราบว่าฟังก์ชั่นเหล่านี้จะไม่ครอบคลุมหน่วยงาน HTML ทั้งหมด แต่เฉพาะคนที่พบมากที่สุดคือ&, <, >, ,' "หากต้องการยกเลิกการซ่อนเอนทิตี HTML ทั้งหมดคุณสามารถใช้ไลบรารีของเขา


-1

ฉันใช้สิ่งนี้ในโครงการของฉัน: ได้แรงบันดาลใจจากคำตอบอื่น ๆแต่ด้วยพารามิเตอร์ที่ปลอดภัยเป็นพิเศษจะมีประโยชน์เมื่อคุณจัดการกับตัวละครที่ได้รับการตกแต่ง

var decodeEntities=(function(){

    var el=document.createElement('div');
    return function(str, safeEscape){

        if(str && typeof str === 'string'){

            str=str.replace(/\</g, '&lt;');

            el.innerHTML=str;
            if(el.innerText){

                str=el.innerText;
                el.innerText='';
            }
            else if(el.textContent){

                str=el.textContent;
                el.textContent='';
            }

            if(safeEscape)
                str=str.replace(/\</g, '&lt;');
        }
        return str;
    }
})();

และมันใช้งานได้เช่น:

var label='safe <b> character &eacute;ntity</b>';
var safehtml='<div title="'+decodeEntities(label)+'">'+decodeEntities(label, true)+'</div>';

-1

คำตอบอื่น ๆ ทั้งหมดที่นี่มีปัญหา

document.createElement ('div') วิธีการ (รวมถึงการใช้ jQuery) ดำเนินการจาวาสคริปต์ใด ๆ ที่ส่งผ่านมัน (ปัญหาด้านความปลอดภัย) และ DOMParser.parseFromString () วิธีการตัดขอบช่องว่าง นี่เป็นวิธีแก้ปัญหาจาวาสคริปต์ที่ไม่มีปัญหา:

function htmlDecode(html) {
    var textarea = document.createElement("textarea");
    html= html.replace(/\r/g, String.fromCharCode(0xe000)); // Replace "\r" with reserved unicode character.
    textarea.innerHTML = html;
    var result = textarea.value;
    return result.replace(new RegExp(String.fromCharCode(0xe000), 'g'), '\r');
}

TextArea ใช้เฉพาะเพื่อหลีกเลี่ยงการเรียกใช้โค้ด js มันผ่านสิ่งเหล่านี้:

htmlDecode('&lt;&amp;&nbsp;&gt;'); // returns "<& >" with non-breaking space.
htmlDecode('  '); // returns "  "
htmlDecode('<img src="dummy" onerror="alert(\'xss\')">'); // Does not execute alert()
htmlDecode('\r\n') // returns "\r\n", doesn't lose the \r like other solutions.

1
ไม่การใช้แท็กอื่นไม่สามารถแก้ไขปัญหาได้ นี้ยังคงเป็นช่องโหว่ XSS htmlDecode("</textarea><img src=x onerror=alert(1)>")ลอง คุณโพสต์สิ่งนี้หลังจากที่ฉันได้ชี้ให้เห็นปัญหานี้ในคำตอบของ Sergio Belevskij
Wladimir Palant

ฉันไม่สามารถทำซ้ำปัญหาที่คุณอธิบายได้ ฉันมีรหัสของคุณใน JsFiddle นี้และไม่มีการแจ้งเตือนปรากฏขึ้นเมื่อทำงาน jsfiddle.net/edsjt15g/1 คุณช่วยดูหน่อยได้ไหม? สิ่งที่เบราว์เซอร์ที่คุณใช้?
EricP

2
ฉันใช้ Firefox Chrome จัดการกับสถานการณ์นี้แตกต่างกันอย่างแท้จริงดังนั้นโค้ดจึงไม่ทำงาน - ไม่ใช่สิ่งที่คุณควรเชื่อถือ
Wladimir Palant

-1
var encodedStr = 'hello &amp; world';

var parser = new DOMParser;
var dom = parser.parseFromString(
    '<!doctype html><body>' + encodedStr,
    'text/html');
var decodedString = dom.body.textContent;

console.log(decodedString);

@Wladimir Palant (ผู้เขียน AdBlock Plus) ได้ให้คำตอบแก่ DOMParser เมื่อ4 ปีก่อน คุณอ่านคำตอบก่อนหน้านี้ก่อนโพสต์ของคุณ?
Dan Dascalescu

-7

มีตัวแปรที่ 80% ที่มีประสิทธิผลเป็นคำตอบที่ด้านบนมาก

ดูมาตรฐาน: https://jsperf.com/decode-html12345678/1

การทดสอบประสิทธิภาพ

console.log(decodeEntities('test: &gt'));

function decodeEntities(str) {
  // this prevents any overhead from creating the object each time
  const el = decodeEntities.element || document.createElement('textarea')

  // strip script/html tags
  el.innerHTML = str
    .replace(/<script[^>]*>([\S\s]*?)<\/script>/gmi, '')
    .replace(/<\/?\w(?:[^"'>]|"[^"]*"|'[^']*')*>/gmi, '');

  return el.value;
}

หากคุณต้องการออกจากแท็กให้ลบการ.replace(...)โทรสองสายออก (คุณสามารถออกจากการโทรครั้งแรกหากคุณไม่ต้องการสคริปต์)


6
ขอแสดงความยินดีคุณสามารถปิดบังช่องโหว่ด้วยตรรกะ sanitizaion ปลอมทั้งหมดเพื่อประสิทธิภาพที่ชนะซึ่งไม่สำคัญในทางปฏิบัติ ลองโทรdecodeEntities("</textarea '><img src=x onerror=alert(1) \">")ใน Firefox โปรดหยุดความพยายามในการฆ่าเชื้อโค้ด HTML ด้วยนิพจน์ทั่วไป
Wladimir Palant
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.