Development Tip

입력 필드에서 속성을 읽을 때 HTML 인코딩이 손실 됨

yourdevel 2020. 9. 29. 18:50
반응형

입력 필드에서 속성을 읽을 때 HTML 인코딩이 손실 됨


숨겨진 필드에서 값을 가져와 텍스트 상자에 표시하기 위해 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;이 유지 되기를 원합니다 .

문자열을 HTML로 인코딩하는 JavaScript 라이브러리 또는 jQuery 메서드가 있습니까?


편집 : 이 답변은 오래 전에 게시되었으며 htmlDecode기능은 XSS 취약점을 도입했습니다. 그것은에서 임시 요소를 변경 수정 된 divA가에 textareaXSS에서의 기회를 감소시킨다. 하지만 요즘에는 다른 anwswer 에서 제안한대로 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함수 I가 설정 innerText요소, 그리고 상기 인코딩 된 검색 innerHTML; htmlDecode기능이 설정 I innerHTML요소의 값과이 innerText검색된다.

여기 에서 실행 예제를 확인 하십시오 .


jQuery 트릭은 따옴표를 인코딩하지 않으며 IE에서는 공백을 제거합니다.

이미 많이 사용 / 테스트 된 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 :
가장 빠른 이스케이프 검색에서이 replaceAll메서드 구현을 찾았습니다 .
http://dumpsite.com/forum/index.php?topic=4.msg29#msg29
(또한 여기에서 참조 : Fastest 문자열에서 모든 문자 인스턴스를 대체하는 방법 )
일부 성능 결과는 다음과 같습니다.
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

몇 가지 개선 사항을 추가합니다. 모호한 유니 코드 문제처리하고 영숫자가 아닌 모든 문자를 엔티티로 변환 하는 것으로 보입니다 . 문서에 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 .html()버전과 버전 보다 훨씬 빠른 비 jQuery 버전입니다 .replace(). 이것은 모든 공백을 유지하지만 jQuery 버전과 마찬가지로 따옴표를 처리하지 않습니다.

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

속도 : http://jsperf.com/htmlencoderegex/17

속도 테스트

데모: jsFiddle

산출:

산출

스크립트:

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 ) ) );

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();
} 

밑줄 제공 _.escape()_.unescape()이를 수행하는 방법.

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

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

좋은 대답입니다. 인코딩 할 값이 undefined또는 nulljQuery 1.4.2 인 경우 다음과 같은 오류가 발생할 수 있습니다.

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

또는

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가 메모리에서 무엇이든 읽기 위해 실행될 때까지 얻는 문자는 인코딩이 나타내는 문자입니다.

여기서 의미론에 대해 엄격하게 작동 할 수 있지만 인코딩의 목적을 이해하기를 원했습니다. "lost"라는 단어는 무언가가 제대로 작동하지 않는 것처럼 들리게합니다.


Prototype 에는 String 클래스가 내장되어 있습니다. 따라서 Prototype을 사용 / 사용할 계획이라면 다음과 같은 작업을 수행합니다.

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

Jquery없이 더 빠릅니다. 문자열의 모든 문자를 인코딩 할 수 있습니다.

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 오브젝트를 확장합니다.

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 method for javascript"를 만들었습니다 .


비슷한 문제가 있었고 encodeURIComponentJavaScript 의 기능 사용하여 해결했습니다 ( 문서 ).

예를 들어, 다음을 사용하는 경우 :

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

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

당신은 얻을 것이다 chalk%20%26%20cheese. 공백도 유지됩니다.

제 경우에는 백 슬래시 하나를 인코딩해야했는데이 코드는 완벽하게 작동합니다.

encodeURIComponent('name/surname')

그리고 나는 얻었다 name%2Fsurname


을 바탕으로 각도의 살균 (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};

자바 스크립트에는 간단한 HTML 인코딩 / 디코딩 메서드가 없습니다.

그러나 할 수있는 일은 JS를 사용하여 임의의 요소를 만들고 내부 텍스트를 설정 한 다음 innerHTML을 사용하여 읽는 것입니다.

jQuery를 사용하면 다음과 같이 작동합니다.

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 등을 삽입하지 않습니다. value속성 (또는 속성, 확실하지 않음) 을 설정하도록 DOM에 지시합니다 . 어느 쪽이든 DOM은 모든 인코딩 문제를 처리합니다. 사용처럼 이상한 일을하지 않는 한 document.write또는 eval효과적으로 투명하게됩니다 HTML 인코딩.

결과를 저장하기 위해 새 텍스트 상자를 생성하는 것에 대해 이야기하는 경우 ... 여전히 쉽습니다. HTML의 정적 부분을 jQuery에 전달한 다음 반환되는 객체에 나머지 속성 / 속성을 설정하면됩니다.

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

내 순수 JS 기능 :

/**
 * HTML entities encode
 *
 * @param {string} str Input text
 * @return {string} Filtered text
 */
function htmlencode (str){

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

JavaScript HTML 엔터티 인코딩 및 디코딩


jQuery를 사용하려는 경우. 나는 이것을 찾았다:

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

(jQuery SDK에서 제공하는 jquery.string 플러그인의 일부)

Prototype의 문제는 JavaScript에서 기본 개체를 확장하고 사용했을 수있는 모든 jQuery와 호환되지 않는다는 것입니다. 물론 jQuery가 아닌 Prototype을 이미 사용하고 있다면 문제가되지 않습니다.

편집 : 또한 jQuery에 대한 Prototype의 문자열 유틸리티 포트 인 이것도 있습니다.

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 '';
    }
  }

내 Domain \ User 문자열에서 백 슬래시와 관련된 몇 가지 문제가 발생했습니다.

나는 이것을 Anentropic의 대답에서 다른 탈출구에 추가했습니다.

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

내가 찾은 것 : JavaScript에서 백 슬래시를 이스케이프하는 방법?


다음 Server.HTMLEncode은 순수한 JavaScript로 작성된 Microsoft 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에서 수행중인 작업 선택

이 스크립트를 추가하면 HTML을 벗어날 수 있습니다.

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);

참고 URL : https://stackoverflow.com/questions/1219860/html-encoding-lost-when-attribute-read-from-input-field

반응형