سؤال

أنا أستخدم JavaScript لسحب قيمة من حقل مخفي وعرضها في مربع نص.يتم ترميز القيمة الموجودة في الحقل المخفي.

على سبيل المثال،

<input id='hiddenId' type='hidden' value='chalk &amp; cheese' />

يتم سحبه إلى

<input type='text' value='chalk &amp; cheese' />

عبر بعض jQuery للحصول على القيمة من الحقل المخفي (في هذه المرحلة أفقد التشفير):

$('#hiddenId').attr('value')

المشكلة هي أنني عندما أقرأ chalk &amp; cheese من الحقل المخفي، يبدو أن JavaScript تفقد الترميز.لا أريد أن تكون القيمة chalk & cheese.أريد الحرفي amp; يتم الاحتفاظ.

هل توجد مكتبة جافا سكريبت أو طريقة jQuery يمكنها ترميز سلسلة بتنسيق HTML؟

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

المحلول

يحرر: تم نشر هذه الإجابة منذ فترة طويلة، و htmlDecode قدمت الوظيفة ثغرة أمنية في XSS.تم تعديله بتغيير العنصر المؤقت من a div إلى أ textarea تقليل فرصة XSS.لكن في الوقت الحاضر، أود أن أشجعك على استخدام DOMParser API كما هو مقترح في إجابة أخرى.


أستخدم هذه الوظائف:

function htmlEncode(value){
  // Create a in-memory element, set its inner text (which is automatically encoded)
  // Then grab the encoded contents back out. The element never exists on the DOM.
  return $('<textarea/>').text(value).html();
}

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

بشكل أساسي، يتم إنشاء عنصر div في الذاكرة، لكن لا يتم إلحاقه بالمستند أبدًا.

على ال htmlEncode وظيفة قمت بتعيين innerText للعنصر، واسترجاع الكود المشفر innerHTML;على ال htmlDecode وظيفة قمت بتعيين innerHTML قيمة العنصر و innerText يتم استرجاعها.

تحقق من مثال قيد التشغيل هنا.

نصائح أخرى

لا تقوم خدعة jQuery بتشفير علامات الاقتباس وفي IE ستزيل المسافة البيضاء.

على أساس يهرب templatetag في Django، والذي أعتقد أنه تم استخدامه/اختباره بكثافة بالفعل، لقد قمت بإنشاء هذه الوظيفة التي تقوم بما هو مطلوب.

يمكن القول إنه أبسط (وربما أسرع) من أي من الحلول البديلة لمشكلة تجريد المسافات البيضاء - ويقوم بتشفير علامات الاقتباس، وهو أمر ضروري إذا كنت ستستخدم النتيجة داخل قيمة سمة على سبيل المثال.

function htmlEscape(str) {
    return str
        .replace(/&/g, '&amp;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#39;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;');
}

// I needed the opposite function today, so adding here too:
function htmlUnescape(str){
    return str
        .replace(/&quot;/g, '"')
        .replace(/&#39;/g, "'")
        .replace(/&lt;/g, '<')
        .replace(/&gt;/g, '>')
        .replace(/&amp;/g, '&');
}

تحديث 2013-06-17:
في البحث عن أسرع الهروب وجدت هذا التنفيذ لـ a replaceAll طريقة:
http://dumpsite.com/forum/index.php?topic=4.msg29#msg29
(المشار إليها أيضًا هنا: أسرع طريقة لاستبدال كافة مثيلات الحرف في سلسلة)
بعض نتائج الأداء هنا:
http://jsperf.com/htmlencoderegex/25

أنه يعطي سلسلة نتائج متطابقة إلى المدمج replace سلاسل أعلاه.سأكون سعيدًا جدًا إذا استطاع شخص ما أن يشرح لماذا هو أسرع!؟

تحديث 2015-03-04:
لقد لاحظت للتو أن AngularJS تستخدم الطريقة المذكورة أعلاه بالضبط:
https://github.com/angular/angular.js/blob/v1.3.14/src/ngSanitize/sanitize.js#L435

يضيفون بعض التحسينات - يبدو أنهم يتعاملون مع ملف مشكلة Unicode غامضة وكذلك تحويل كافة الأحرف غير الأبجدية الرقمية إلى كيانات.كان لدي انطباع بأن هذا الأخير لم يكن ضروريًا طالما أن لديك مجموعة أحرف UTF8 محددة للمستند الخاص بك.

سألاحظ أنه (بعد 4 سنوات) لا يزال Django لا يقوم بأي من هذه الأشياء، لذلك لست متأكدًا من مدى أهميتها:
https://github.com/django/django/blob/1.8b1/django/utils/html.py#L44

تحديث 2016-04-06:
قد ترغب أيضًا في الهروب من الشرطة المائلة للأمام /.هذا ليس مطلوبًا لترميز HTML الصحيح، ولكنه كذلك موصى به من قبل OWASP كإجراء أمان لمكافحة XSS.(شكرًا لـJNF لاقتراح ذلك في التعليقات)

        .replace(/\//g, '&#x2F;');

إليك إصدارًا غير jQuery وهو أسرع بكثير من كلا الإصدارين jQuery .html() النسخة و .replace() إصدار.يحافظ هذا على كل المسافات البيضاء، ولكن مثل إصدار jQuery، لا يتعامل مع علامات الاقتباس.

function htmlEncode( html ) {
    return document.createElement( 'a' ).appendChild( 
        document.createTextNode( html ) ).parentNode.innerHTML;
};

سرعة: http://jsperf.com/htmlencoderegex/17

speed test

العرض التوضيحي: jsFiddle

انتاج:

output

النصي:

function htmlEncode( html ) {
    return document.createElement( 'a' ).appendChild( 
        document.createTextNode( html ) ).parentNode.innerHTML;
};

function htmlDecode( html ) {
    var a = document.createElement( 'a' ); a.innerHTML = html;
    return a.textContent;
};

document.getElementById( 'text' ).value = htmlEncode( document.getElementById( 'hidden' ).value );

//sanity check
var html = '<div>   &amp; hello</div>';
document.getElementById( 'same' ).textContent = 
      'html === htmlDecode( htmlEncode( html ) ): ' 
    + ( html === htmlDecode( htmlEncode( html ) ) );

لغة البرمجة:

<input id="hidden" type="hidden" value="chalk    &amp; cheese" />
<input id="text" value="" />
<div id="same"></div>

وأعرف أن هذا هو واحد من العمر، ولكن أردت أن الرد على الاختلاف من الجواب المقبول التي ستعمل في IE دون إزالة خطوط:

function multiLineHtmlEncode(value) {
    var lines = value.split(/\r\n|\r|\n/);
    for (var i = 0; i < lines.length; i++) {
        lines[i] = htmlEncode(lines[i]);
    }
    return lines.join('\r\n');
}

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

تؤكد يوفر <لأ href = "http://underscorejs.org/#escape" يختلط = "noreferrer" > _.escape() و _.unescape() الأساليب التي تفعل ذلك.

> _.unescape( "chalk &amp; cheese" );
  "chalk & cheese"

> _.escape( "chalk & cheese" );
  "chalk &amp; cheese"

وإجابة جيدة. لاحظ أنه إذا كانت قيمة لترميز هي undefined أو null مع 1.4.2 مسج قد تحصل أخطاء مثل:

وjQuery("<div/>").text(value).html is not a function

وOR

وUncaught TypeError: Object has no method 'html'

والحل هو تعديل وظيفة للتحقق من قيمة الفعلية:

function htmlEncode(value){ 
    if (value) {
        return jQuery('<div/>').text(value).html(); 
    } else {
        return '';
    }
}

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

function escapeHTML (str)
{
    var div = document.createElement('div');
    var text = document.createTextNode(str);
    div.appendChild(text);
    return div.innerHTML;
}

وFWIW، لا تضيع الترميز. يستخدم الترميز بواسطة محلل الترميز (المتصفح) أثناء تحميل الصفحة. بمجرد قراءة المصدر وتحليل والمتصفح لديه DOM تحميلها في الذاكرة، وقد تم تحليل الترميز إلى ما تمثله. حتى في الوقت JS الخاص بك هو تنفيذ لقراءة أي شيء في الذاكرة، وشار الذي تحصل عليه هو ما يمثل الترميز.

وأنا يمكن أن تعمل بشكل صارم على دلالات هنا، ولكني أردت أن تفهم الغرض من الترميز. كلمة "فقدت" يجعل الأمر يبدو وكأنه شيء لا يعمل كما ينبغي.

نموذج أنها لم المدمج في في فئة سلسلة . حتى إذا كنت تستخدم / خطة لاستخدام النموذج، فإنه لا شيء من هذا القبيل:

'<div class="article">This is an article</div>'.escapeHTML();
// -> "&lt;div class="article"&gt;This is an article&lt;/div&gt;"

وأسرع دون مسج. يمكنك ترميز كل حرف في سلسلة الخاص بك:

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

وأو استهداف فقط الشخصيات الرئيسية ما يدعو للقلق (و، inebreaks، <،>، "و") مثل:

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

test.value=encode('Encode HTML entities!\n\n"Safe" escape <script id=\'\'> & useful in <pre> tags!');

testing.innerHTML=test.value;

/*************
* \x26 is &ampersand (it has to be first),
* \x0A is newline,
*************/
<textarea id=test rows="9" cols="55"></textarea>

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

وهنا هو الحل جافا سكريبت بسيط. ويمتد الكائن سلسلة مع طريقة "HTMLEncode" والتي يمكن استخدامها على كائن بدون المعلمة، أو مع المعلمة.

String.prototype.HTMLEncode = function(str) {
  var result = "";
  var str = (arguments.length===1) ? str : this;
  for(var i=0; i<str.length; i++) {
     var chrcode = str.charCodeAt(i);
     result+=(chrcode>128) ? "&#"+chrcode+";" : str.substr(i,1)
   }
   return result;
}
// TEST
console.log("stetaewteaw æø".HTMLEncode());
console.log("stetaewteaw æø".HTMLEncode("æåøåæå"))

ولقد جعلت من جوهر "طريقة HTMLEncode جافا سكريبت" .

مرتكز على تعقيم الزاوي...(بناء جملة الوحدة النمطية es6)

// ref: https://github.com/angular/angular.js/blob/v1.3.14/src/ngSanitize/sanitize.js
const SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
const NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g;

const decodeElem = document.createElement('pre');


/**
 * Decodes html encoded text, so that the actual string may
 * be used.
 * @param value
 * @returns {string} decoded text
 */
export function decode(value) {
  if (!value) return '';
  decodeElem.innerHTML = value.replace(/</g, '&lt;');
  return decodeElem.textContent;
}


/**
 * Encodes all potentially dangerous characters, so that the
 * resulting string can be safely inserted into attribute or
 * element text.
 * @param value
 * @returns {string} encoded text
 */
export function encode(value) {
  if (value === null || value === undefined) return '';
  return String(value).
    replace(/&/g, '&amp;').
    replace(SURROGATE_PAIR_REGEXP, value => {
      var hi = value.charCodeAt(0);
      var low = value.charCodeAt(1);
      return '&#' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';';
    }).
    replace(NON_ALPHANUMERIC_REGEXP, value => {
      return '&#' + value.charCodeAt(0) + ';';
    }).
    replace(/</g, '&lt;').
    replace(/>/g, '&gt;');
}

export default {encode,decode};

وAFAIK ليس هناك أي التوالي إلى الأمام HTML شفر / طرق فك في جافا سكريبت.

ولكن ما يمكنك القيام به، هو استخدام JS لخلق عنصر التعسفي، لأنها مجموعة من النص الداخلي، ثم تلا ذلك باستخدام HTML داخلي.

ويقول، مع مسج هذا يجب أن تعمل:

var helper = $('chalk & cheese').hide().appendTo('body');
var htmled = helper.html();
helper.remove();

وأو شيء على طول هذه الخطوط

يجب أن لا يكون لديك للهروب القيم / ترميز لمكوك لهم من حقل إدخال واحد إلى آخر.

<form>
 <input id="button" type="button" value="Click me">
 <input type="hidden" id="hiddenId" name="hiddenId" value="I like cheese">
 <input type="text" id="output" name="output">
</form>
<script>
    $(document).ready(function(e) {
        $('#button').click(function(e) {
            $('#output').val($('#hiddenId').val());
        });
    });
</script>

وJS لا تذهب إدراج HTML الخام أو أي شيء. انها مجرد يحكي DOM لتعيين الخاصية value (أو سمة، لست متأكدا). وفي كلتا الحالتين، فإن DOM يعالج أي مشاكل الترميز لك. إلا إذا كنت تفعل شيئا غريبا مثل استخدام document.write أو eval، سوف HTML ترميز تكون شفافة على نحو فعال.

إذا كنت تتحدث عن تولد النص الجديد لعقد النتيجة ... انها لا تزال سهلا كما. يمر جزء ثابت من HTML إلى مسج، ثم قم بتعيين بقية خصائص / سمات على الكائن فإنه يعود لك.

$box = $('<input type="text" name="whatever">').val($('#hiddenId').val());

إذا كنت ترغب في استخدام مسج. لقد وجدت هذا:

http://www.jquerysdk.com/api/jQuery.htmlspecialchars

و(جزء من البرنامج المساعد jquery.string التي تقدمها مسج SDK)

والمشكلة مع نموذج أعتقد هو أنه يمتد كائنات قاعدة في جافا سكريبت وسوف تكون غير متوافقة مع أي مسج كنت قد استخدمت. بالطبع، إذا كنت تستخدم بالفعل النموذج وليس مسج، فإنه لن يكون هناك مشكلة.

وتحرير: أيضا هناك هذا، وهو ميناء المرافق سلسلة نموذج للمسج:

http://stilldesigning.com/dotstring/

var htmlEnDeCode = (function() {
    var charToEntityRegex,
        entityToCharRegex,
        charToEntity,
        entityToChar;

    function resetCharacterEntities() {
        charToEntity = {};
        entityToChar = {};
        // add the default set
        addCharacterEntities({
            '&amp;'     :   '&',
            '&gt;'      :   '>',
            '&lt;'      :   '<',
            '&quot;'    :   '"',
            '&#39;'     :   "'"
        });
    }

    function addCharacterEntities(newEntities) {
        var charKeys = [],
            entityKeys = [],
            key, echar;
        for (key in newEntities) {
            echar = newEntities[key];
            entityToChar[key] = echar;
            charToEntity[echar] = key;
            charKeys.push(echar);
            entityKeys.push(key);
        }
        charToEntityRegex = new RegExp('(' + charKeys.join('|') + ')', 'g');
        entityToCharRegex = new RegExp('(' + entityKeys.join('|') + '|&#[0-9]{1,5};' + ')', 'g');
    }

    function htmlEncode(value){
        var htmlEncodeReplaceFn = function(match, capture) {
            return charToEntity[capture];
        };

        return (!value) ? value : String(value).replace(charToEntityRegex, htmlEncodeReplaceFn);
    }

    function htmlDecode(value) {
        var htmlDecodeReplaceFn = function(match, capture) {
            return (capture in entityToChar) ? entityToChar[capture] : String.fromCharCode(parseInt(capture.substr(2), 10));
        };

        return (!value) ? value : String(value).replace(entityToCharRegex, htmlDecodeReplaceFn);
    }

    resetCharacterEntities();

    return {
        htmlEncode: htmlEncode,
        htmlDecode: htmlDecode
    };
})();

وهذا من شفرة المصدر ExtJS.

<script>
String.prototype.htmlEncode = function () {
    return String(this)
        .replace(/&/g, '&amp;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#39;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;');

}

var aString = '<script>alert("I hack your site")</script>';
console.log(aString.htmlEncode());
</script>

وويل الإخراج: &lt;script&gt;alert(&quot;I hack your site&quot;)&lt;/script&gt;

و.htmlEncode () سوف تكون متاحة على كافة السلاسل مرة واحدة محددة.

وHtmlEncodes القيمة المعطاة

  var htmlEncodeContainer = $('<div />');
  function htmlEncode(value) {
    if (value) {
      return htmlEncodeContainer.text(value).html();
    } else {
      return '';
    }
  }

وأنا واجهت بعض القضايا مع مائل في بلدي المجال \ سلسلة العضو.

وأضفت ذلك إلى هروب أخرى من الإجابة Anentropic ل

.replace(/\\/g, '&#92;')

والتي وجدت هنا: كيفية الهروب مائل في جافا سكريبت؟

إليك قليلا الذي يحاكي وظيفة Server.HTMLEncode من ASP مايكروسوفت، وكتب في جافا سكريبت النقي:

function htmlEncode(s) {
  var ntable = {
    "&": "amp",
    "<": "lt",
    ">": "gt",
    "\"": "quot"
  };
  s = s.replace(/[&<>"]/g, function(ch) {
    return "&" + ntable[ch] + ";";
  })
  s = s.replace(/[^ -\x7e]/g, function(ch) {
    return "&#" + ch.charCodeAt(0).toString() + ";";
  });
  return s;
}

وكانت النتيجة <م> لا الفواصل العليا ترميز، ولكن بترميز أخرى HTML العروض الخاصة وأي حرف خارج نطاق 0x20-0x7e.

واختيار ما escapeHTML() تقوم به في prototype.js

وإضافة هذا السيناريو يساعدك escapeHTML:

String.prototype.escapeHTML = function() { 
    return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;')
}

والآن يمكنك استدعاء الأسلوب escapeHTML على السلاسل في السيناريو الخاص بك، مثل:

var escapedString = "<h1>this is HTML</h1>".escapeHTML();
// gives: "&lt;h1&gt;this is HTML&lt;/h1&gt;"

ونأمل أن يساعد أي شخص يبحث عن حل بسيط دون الحاجة لتشمل prototype.js كامل

وعن طريق بعض الإجابات الأخرى هنا أنا قدمت النسخة الذي يحل محل جميع الشخصيات ذات الصلة في مرور واحد بغض النظر عن عدد الأحرف المشفرة مميزة (مكالمة واحدة فقط لreplace()) لذلك سيكون أسرع سلاسل أكبر.

وانها لا تعتمد على DOM API في الوجود أو في مكتبات أخرى.

window.encodeHTML = (function() {
    function escapeRegex(s) {
        return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
    }
    var encodings = {
        '&'  : '&amp;',
        '"'  : '&quot;',
        '\'' : '&#39;',
        '<'  : '&lt;',
        '>'  : '&gt;',
        '\\' : '&#x2F;'
    };
    function encode(what) { return encodings[what]; };
    var specialChars = new RegExp('[' +
        escapeRegex(Object.keys(encodings).join('')) +
    ']', 'g');

    return function(text) { return text.replace(specialChars, encode); };
})();

وبعد أن ركض أن مرة واحدة، يمكنك الاتصال الآن

encodeHTML('<>&"\'')

لتحصل &lt;&gt;&amp;&quot;&#39;

function encodeHTML(str) {
    return document.createElement("a").appendChild( 
        document.createTextNode(str)).parentNode.innerHTML;
};

function decodeHTML(str) {
    var element = document.createElement("a"); 
    element.innerHTML = str;
    return element.textContent;
};
var str = "<"
var enc = encodeHTML(str);
var dec = decodeHTML(enc);
console.log("str: " + str, "\nenc: " + enc, "\ndec: " + dec);

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top