سؤال

هل يعرف أحد طريقة سهلة للهروب من HTML من السلاسل الموجودة في مسج؟أحتاج إلى أن أكون قادرًا على تمرير سلسلة عشوائية وإفلاتها بشكل صحيح لعرضها في صفحة HTML (منع هجمات حقن JavaScript/HTML).أنا متأكد من أنه من الممكن توسيع jQuery للقيام بذلك، لكني لا أعرف ما يكفي عن إطار العمل في الوقت الحالي لإنجاز هذا.

هل كانت مفيدة؟

المحلول

منذ كنت تستخدم مسج, ، يمكنك فقط تعيين العنصر text ملكية:

// before:
// <div class="someClass">text</div>
var someHtmlString = "<script>alert('hi!');</script>";

// set a DIV's text:
$("div.someClass").text(someHtmlString);
// after: 
// <div class="someClass">&lt;script&gt;alert('hi!');&lt;/script&gt;</div>

// get the text in a string:
var escaped = $("<div>").text(someHtmlString).html();
// value: 
// &lt;script&gt;alert('hi!');&lt;/script&gt;

نصائح أخرى

يوجد ايضا الحل من mustache.js

var entityMap = {
  '&': '&amp;',
  '<': '&lt;',
  '>': '&gt;',
  '"': '&quot;',
  "'": '&#39;',
  '/': '&#x2F;',
  '`': '&#x60;',
  '=': '&#x3D;'
};

function escapeHtml (string) {
  return String(string).replace(/[&<>"'`=\/]/g, function (s) {
    return entityMap[s];
  });
}
$('<div/>').text('This is fun & stuff').html(); // "This is fun &amp; stuff"

مصدر: http://debuggable.com/posts/encode-html-entities-with-jquery:480f4dd6-13cc-4ce9-8071-4710cbdd56cb

إذا كنت تهرب إلى HTML، فهناك ثلاثة فقط أعتقد أنها ستكون ضرورية حقًا:

html.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");

اعتمادًا على حالة الاستخدام الخاصة بك، قد تحتاج أيضًا إلى القيام بأشياء مثل " ل &quot;.إذا أصبحت القائمة كبيرة بما يكفي، فسأستخدم مصفوفة فقط:

var escaped = html;
var findReplace = [[/&/g, "&amp;"], [/</g, "&lt;"], [/>/g, "&gt;"], [/"/g, "&quot;"]]
for(var item in findReplace)
    escaped = escaped.replace(findReplace[item][0], findReplace[item][1]);

encodeURIComponent() سيتم الهروب منه فقط لعناوين URL، وليس لـ HTML.

لقد كتبت وظيفة صغيرة جدًا تقوم بذلك.إنه يهرب فقط ", &, < و > (ولكن عادة هذا هو كل ما تحتاجه على أي حال).إنه أكثر أناقة قليلاً من الحلول المقترحة سابقًا من حيث أنه يستخدم فقط واحد .replace() للقيام بكل التحويل.(تحرير 2: تقليل تعقيد التعليمات البرمجية مما يجعل الوظيفة أصغر حجمًا وأكثر دقة، إذا كنت مهتمًا بالرمز الأصلي، فراجع نهاية هذه الإجابة.)

function escapeHtml(text) {
    'use strict';
    return text.replace(/[\"&<>]/g, function (a) {
        return { '"': '&quot;', '&': '&amp;', '<': '&lt;', '>': '&gt;' }[a];
    });
}

هذا جافا سكريبت عادي، ولم يتم استخدام jQuery.

الهروب / و ' أيضاً

تحرير ردا على com.mklementتعليق.

يمكن توسيع الوظيفة المذكورة أعلاه بسهولة لتشمل أي حرف.لتحديد المزيد من الأحرف للهروب، ما عليك سوى إدراجهما في فئة الأحرف في التعبير العادي (أي:داخل /[...]/g) وكمدخل في chr هدف.(تحرير 2: تم اختصار هذه الوظيفة أيضًا بنفس الطريقة.)

function escapeHtml(text) {
    'use strict';
    return text.replace(/[\"&'\/<>]/g, function (a) {
        return {
            '"': '&quot;', '&': '&amp;', "'": '&#39;',
            '/': '&#47;',  '<': '&lt;',  '>': '&gt;'
        }[a];
    });
}

لاحظ الاستخدام أعلاه &#39; للفاصلة العليا (الكيان الرمزي &apos; ربما تم استخدامه بدلاً من ذلك - تم تعريفه في XML، ولكن لم يتم تضمينه في الأصل في مواصفات HTML وبالتالي قد لا يكون مدعومًا من قبل جميع المتصفحات.يرى: مقالة ويكيبيديا عن ترميزات أحرف HTML).وأذكر أيضًا أنني قرأت في مكان ما أن استخدام الكيانات العشرية مدعوم على نطاق أوسع من استخدام النظام السداسي العشري، لكن يبدو أنه لا يمكنني العثور على المصدر لذلك الآن.(ولا يمكن أن يكون هناك العديد من المتصفحات التي لا تدعم الكيانات السداسية العشرية.)

ملحوظة: إضافة / و ' إن إدراج قائمة الأحرف التي تم الهروب منها ليس مفيدًا تمامًا، نظرًا لأنها لا تحتوي على أي معنى خاص في HTML ولا تفعل ذلك يحتاج ليتم الهروب.

إبداعي escapeHtml وظيفة

تحرير 2: استخدمت الدالة الأصلية متغيرًا (chr) لتخزين الكائن المطلوب لـ .replace() أتصل مرة أخرى.يحتاج هذا المتغير أيضًا إلى وظيفة مجهولة إضافية لتحديد نطاقه، مما يجعل الوظيفة (بدون داعٍ) أكبر قليلاً وأكثر تعقيدًا.

var escapeHtml = (function () {
    'use strict';
    var chr = { '"': '&quot;', '&': '&amp;', '<': '&lt;', '>': '&gt;' };
    return function (text) {
        return text.replace(/[\"&<>]/g, function (a) { return chr[a]; });
    };
}());

لم أختبر أي من الإصدارين أسرع.إذا قمت بذلك، فلا تتردد في إضافة معلومات وروابط حول هذا الموضوع هنا.

من السهل بما فيه الكفاية استخدام الشرطة السفلية:

_.escape(string) 

تسطير أسفل السطر هي مكتبة أدوات مساعدة توفر الكثير من الميزات التي لا توفرها لغة js الأصلية.هناك ايضا لوداش وهي نفس واجهة برمجة التطبيقات (API) مثل الشرطة السفلية ولكن تمت إعادة كتابتها لتكون أكثر أداءً.

أدرك مدى تأخري في حضور هذه الحفلة، ولكن لدي حل سهل للغاية لا يتطلب jQuery.

escaped = new Option(unescaped).innerHTML;

يحرر:هذا لا يفلت من الاقتباسات.الحالة الوحيدة التي يلزم فيها تجاوز علامات الاقتباس هي إذا كان سيتم لصق المحتوى سطريًا في إحدى السمات ضمن سلسلة HTML.من الصعب بالنسبة لي أن أتخيل حالة يكون فيها القيام بذلك تصميمًا جيدًا.

تحرير 2:إذا كان الأداء أمرًا بالغ الأهمية، فإن الحل الأعلى أداءً (بحوالي 50%) لا يزال عبارة عن سلسلة من استبدالات التعبير العادي.ستكتشف المتصفحات الحديثة أن التعبيرات العادية لا تحتوي على عوامل تشغيل، بل مجرد سلسلة، وستدمجها جميعًا في عملية واحدة.

إليك وظيفة JavaScript نظيفة وواضحة.سيتم تخطي النص مثل "عدد قليل < كثير "إلى" عدد قليل <كثير".

function escapeHtmlEntities (str) {
  if (typeof jQuery !== 'undefined') {
    // Create an empty div to use as a container,
    // then put the raw text in and get the HTML
    // equivalent out.
    return jQuery('<div/>').text(str).html();
  }

  // No jQuery, so use string replace.
  return str
    .replace(/&/g, '&amp;')
    .replace(/>/g, '&gt;')
    .replace(/</g, '&lt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&apos;');
}

بعد الاختبارات الأخيرة يمكنني أن أوصي الأسرع وبشكل كامل عبر المتصفح متناسق جافا سكريبت الأصلي (دوم) الحل:

function HTMLescape(html){
    return document.createElement('div')
        .appendChild(document.createTextNode(html))
        .parentNode
        .innerHTML
}

إذا كررت ذلك عدة مرات، فيمكنك القيام بذلك باستخدام المتغيرات التي تم إعدادها مرة واحدة:

//prepare variables
var DOMtext = document.createTextNode("test");
var DOMnative = document.createElement("span");
DOMnative.appendChild(DOMtext);

//main work for each case
function HTMLescape(html){
  DOMtext.nodeValue = html;
  return DOMnative.innerHTML
}

انظر إلى أدائي النهائي مقارنة (سؤال المكدس).

يحاول تسطير أسفل السطر lib، وهو يعمل مع jQuery.

_.str.escapeHTML('<div>Blah blah blah</div>')

انتاج:

'&lt;div&gt;Blah blah blah&lt;/div&gt;'

لقد قمت بتحسين مثال mustache.js بإضافة ملف escapeHTML() طريقة لكائن السلسلة.

var __entityMap = {
    "&": "&amp;",
    "<": "&lt;",
    ">": "&gt;",
    '"': '&quot;',
    "'": '&#39;',
    "/": '&#x2F;'
};

String.prototype.escapeHTML = function() {
    return String(this).replace(/[&<>"'\/]/g, function (s) {
        return __entityMap[s];
    });
}

بهذه الطريقة يكون الاستخدام سهلاً للغاية "Some <text>, more Text&Text".escapeHTML()

escape() و unescape() تهدف إلى تشفير/فك تشفير السلاسل لعناوين URL، وليس HTML.

في الواقع، أستخدم المقتطف التالي للقيام بالخدعة التي لا تتطلب أي إطار عمل:

var escapedHtml = html.replace(/&/g, '&amp;')
                      .replace(/>/g, '&gt;')
                      .replace(/</g, '&lt;')
                      .replace(/"/g, '&quot;')
                      .replace(/'/g, '&apos;');

إذا كان لديك underscore.js، استخدم _.escape (أكثر كفاءة من طريقة jQuery المنشورة أعلاه):

_.escape('Curly, Larry & Moe'); // returns: Curly, Larry &amp; Moe

إذا كنت تسلك مسار regex، فهناك خطأ في مثال tghw أعلاه.

<!-- WON'T WORK -  item[0] is an index, not an item -->

var escaped = html; 
var findReplace = [[/&/g, "&amp;"], [/</g, "&lt;"], [/>/g,"&gt;"], [/"/g,
"&quot;"]]

for(var item in findReplace) {
     escaped = escaped.replace(item[0], item[1]);   
}


<!-- WORKS - findReplace[item[]] correctly references contents -->

var escaped = html;
var findReplace = [[/&/g, "&amp;"], [/</g, "&lt;"], [/>/g, "&gt;"], [/"/g, "&quot;"]]

for(var item in findReplace) {
     escaped = escaped.replace(findReplace[item[0]], findReplace[item[1]]);
}

وهذا مثال آمن لطيف ...

function escapeHtml(str) {
    if (typeof(str) == "string"){
        try{
            var newStr = "";
            var nextCode = 0;
            for (var i = 0;i < str.length;i++){
                nextCode = str.charCodeAt(i);
                if (nextCode > 0 && nextCode < 128){
                    newStr += "&#"+nextCode+";";
                }
                else{
                    newStr += "?";
                }
             }
             return newStr;
        }
        catch(err){
        }
    }
    else{
        return str;
    }
}

يمكنك القيام بذلك بسهولة باستخدام Vanilla JS.

ما عليك سوى إضافة عقدة نصية للمستند.سيتم الهروب منه بواسطة المتصفح.

var escaped = document.createTextNode("<HTML TO/ESCAPE/>")
document.getElementById("[PARENT_NODE]").appendChild(escaped)
(function(undefined){
    var charsToReplace = {
        '&': '&amp;',
        '<': '&lt;',
        '>': '&gt;'
    };

    var replaceReg = new RegExp("[" + Object.keys(charsToReplace).join("") + "]", "g");
    var replaceFn = function(tag){ return charsToReplace[tag] || tag; };

    var replaceRegF = function(replaceMap) {
        return (new RegExp("[" + Object.keys(charsToReplace).concat(Object.keys(replaceMap)).join("") + "]", "gi"));
    };
    var replaceFnF = function(replaceMap) {
        return function(tag){ return replaceMap[tag] || charsToReplace[tag] || tag; };
    };

    String.prototype.htmlEscape = function(replaceMap) {
        if (replaceMap === undefined) return this.replace(replaceReg, replaceFn);
        return this.replace(replaceRegF(replaceMap), replaceFnF(replaceMap));
    };
})();

لا توجد متغيرات عامة، بعض تحسين الذاكرة.الاستخدام:

"some<tag>and&symbol©".htmlEscape({'©': '&copy;'})

النتيجة هي:

"some&lt;tag&gt;and&amp;symbol&copy;"
function htmlEscape(str) {
    var stringval="";
    $.each(str, function (i, element) {
        alert(element);
        stringval += element
            .replace(/&/g, '&amp;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&#39;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(' ', '-')
            .replace('?', '-')
            .replace(':', '-')
            .replace('|', '-')
            .replace('.', '-');
    });
    alert(stringval);
    return String(stringval);
}

طريقتان بسيطتان لا تتطلبان أي JQUERY...

أنت تستطيع تشفير كافة الأحرف في السلسلة الخاصة بك مثل هذا:

function encode(e){return e.replace(/[^]/g,function(e){return"&#"+e.charCodeAt(0)+";"})}

أو فقط استهداف الشخصيات الرئيسية للقلق &, ، فواصل الأسطر، <, >, " و ' يحب:

function encode(r){
return r.replace(/[\x26\x0A\<>'"]/g,function(r){return"&#"+r.charCodeAt(0)+";"})
}

var myString='Encode HTML entities!\n"Safe" escape <script></'+'script> & other tags!';

test.value=encode(myString);

testing.innerHTML=encode(myString);

/*************
* \x26 is &ampersand (it has to be first),
* \x0A is newline,
*************/
<p><b>What JavaScript Generated:</b></p>

<textarea id=test rows="3" cols="55"></textarea>

<p><b>What It Renders Too In HTML:</b></p>

<div id="testing">www.WHAK.com</div>

مثال بسيط للهروب من جافا سكريبت:

function escapeHtml(text) {
    var div = document.createElement('div');
    div.innerText = text;
    return div.innerHTML;
}

escapeHtml("<script>alert('hi!');</script>")
// "&lt;script&gt;alert('hi!');&lt;/script&gt;"
function htmlDecode(t){
   if (t) return $('<div />').html(t).text();
}

يعمل كالسحر

هذه الإجابة يوفر طرق jQuery وJS العادية، ولكن هذا أقصر بدون استخدام DOM:

unescape(escape("It's > 20% less complicated this way."))

سلسلة الهروب: It%27s%20%3E%2020%25%20less%20complicated%20this%20way.

إذا كانت المساحات الهاربة تزعجك، فحاول:

unescape(escape("It's > 20% less complicated this way.").replace(/%20/g, " "))

سلسلة الهروب: It%27s %3E 20%25 less complicated this way.

لسوء الحظ، ال escape() كانت الوظيفة تم إهماله في إصدار JavaScript 1.5. encodeURI() أو encodeURIComponent() هي البدائل، لكنهم يتجاهلون ', ، وبالتالي فإن السطر الأخير من التعليمات البرمجية سيتحول إلى هذا:

decodeURI(encodeURI("It's > 20% less complicated this way.").replace(/%20/g, " ").replace("'", '%27'))

لا تزال جميع المتصفحات الرئيسية تدعم الرمز القصير، ونظرًا لعدد المواقع القديمة، أشك في أن هذا سيتغير قريبًا.

إذا كنت تقوم بحفظ هذه المعلومات في ملف قاعدة البيانات, فمن الخطأ الهروب من HTML باستخدام ملف جانب العميل البرنامج النصي، وينبغي أن يتم ذلك في الخادم.وإلا فمن السهل تجاوز حماية XSS الخاصة بك.

لتوضيح وجهة نظري، إليك مثال باستخدام إحدى الإجابات:

لنفترض أنك تستخدم وظيفة escapeHtml للهروب من HTML من تعليق في مدونتك ثم نشره على الخادم الخاص بك.

var entityMap = {
    "&": "&amp;",
    "<": "&lt;",
    ">": "&gt;",
    '"': '&quot;',
    "'": '&#39;',
    "/": '&#x2F;'
  };

  function escapeHtml(string) {
    return String(string).replace(/[&<>"'\/]/g, function (s) {
      return entityMap[s];
    });
  }

يمكن للمستخدم:

  • قم بتحرير معلمات طلب POST واستبدل التعليق بكود جافا سكريبت.
  • قم بالكتابة فوق وظيفة escapeHtml باستخدام وحدة تحكم المتصفح.

إذا قام المستخدم بلصق هذا المقتطف في وحدة التحكم، فسيتجاوز التحقق من صحة XSS:

function escapeHtml(string){
   return string
}

جميع الحلول عديمة الفائدة إذا لم تمنع إعادة الهروب، على سبيل المثال.ستستمر معظم الحلول في الهروب & ل &amp;.

escapeHtml = function (s) {
    return s ? s.replace(
        /[&<>'"]/g,
        function (c, offset, str) {
            if (c === "&") {
                var substr = str.substring(offset, offset + 6);
                if (/&(amp|lt|gt|apos|quot);/.test(substr)) {
                    // already escaped, do not re-escape
                    return c;
                }
            }
            return "&" + {
                "&": "amp",
                "<": "lt",
                ">": "gt",
                "'": "apos",
                '"': "quot"
            }[c] + ";";
        }
    ) : "";
};
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top