从输入字段读取属性时,HTML编码丢失
-
10-07-2019 - |
题
我<!>#8217;使用JavaScript从隐藏字段中提取值并将其显示在文本框中。隐藏字段中的值已编码。
例如,
<input id='hiddenId' type='hidden' value='chalk & cheese' />
被拉入
<input type='text' value='chalk & cheese' />
通过一些jQuery从隐藏字段中获取值(<!>#8217; s此时我丢失了编码):
$('#hiddenId').attr('value')
问题在于,当我从隐藏字段中读取chalk & cheese
时,JavaScript似乎失去了编码。我不希望该值为chalk & cheese
。我希望保留文字amp;
。
是否存在对字符串进行HTML编码的JavaScript库或jQuery方法?
解决方案
编辑:此答案很久以前就已发布,而htmlDecode
函数引入了XSS漏洞。它已被修改,将临时元素从div
更改为textarea
以减少XSS机会。但是现在,我建议您按照其他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
函数中,我设置元素的innerText
,并检索编码的innerHTML
;在<=>函数中,我设置元素的<=>值,并检索<=>。
查看此处的正在运行的示例。
其他提示
jQuery技巧不对引号进行编码,在IE中它会剥离你的空格。
基于Django中的转义模板标签,我猜我已经大量使用/测试了,我做了这个功能,可以满足需要。
它可以说比空白剥离问题的任何变通方法更简单(也可能更快) - 它编码引号,如果您要在属性值中使用结果,这是必不可少的。
function htmlEscape(str) {
return str
.replace(/&/g, '&')
.replace(/"/g, '"')
.replace(/'/g, ''')
.replace(/</g, '<')
.replace(/>/g, '>');
}
// I needed the opposite function today, so adding here too:
function htmlUnescape(str){
return str
.replace(/"/g, '"')
.replace(/'/g, "'")
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/&/g, '&');
}
更新2013-06-17:
在寻找最快的转义时,我发现了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/斑点/ 1.8b1 / django的/ utils的/ html.py#L44
更新2016-04-06:
您可能还希望逃避正斜杠/
。这不是正确的HTML编码所必需的,但它是推荐由OWASP 作为反XSS安全措施。 (感谢@JNF在评论中提出建议)
.replace(/\//g, '/');
这是一个非jQuery版本,它比jQuery .html()
版本和.replace()
版本快得多。这保留了所有空格,但是像jQuery版本一样,不处理引号。
function htmlEncode( html ) {
return document.createElement( 'a' ).appendChild(
document.createTextNode( html ) ).parentNode.innerHTML;
};
速度: http://jsperf.com/htmlencoderegex/17
输出:
脚本:
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> & hello</div>';
document.getElementById( 'same' ).textContent =
'html === htmlDecode( htmlEncode( html ) ): '
+ ( html === htmlDecode( htmlEncode( html ) ) );
HTML:
<input id="hidden" type="hidden" value="chalk & 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 & cheese" );
"chalk & cheese"
> _.escape( "chalk & cheese" );
"chalk & cheese"
好的答案。请注意,如果要使用jQuery 1.4.2编码的值为undefined
或null
,则可能会出现以下错误:
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 '';
}
}
对于那些喜欢普通javascript的人来说,这是我成功使用的方法:
function escapeHTML (str)
{
var div = document.createElement('div');
var text = document.createTextNode(str);
div.appendChild(text);
return div.innerHTML;
}
FWIW,编码不会丢失。在页面加载期间,标记解析器(浏览器)使用编码。一旦读取并解析了源并且浏览器将DOM加载到内存中,编码就会被解析为它所代表的内容。因此,当您的JS执行以读取内存中的任何内容时,它获取的char就是编码所代表的内容。
我可能在这里严格操作语义,但我希望你理解编码的目的。单词<!>“;丢失<!>”;听起来好像有些东西没有像它应该的那样工作。
没有Jquery更快。您可以对字符串中的每个字符进行编码:
function encode(e){return e.replace(/[^]/g,function(e){return"&#"+e.charCodeAt(0)+";"})}
或者只是针对主要人物担心(<!> amp;,inebreaks,<!> lt;,<!> gt;,<!>;和'),如:
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 &ersand (it has to be first),
* \x0A is newline,
*************/
<textarea id=test rows="9" cols="55"></textarea>
<div id="testing">www.WHAK.com</div>
这是一个简单的JavaScript解决方案。它使用方法<!>引用扩展String对象; HTMLEncode <!> quot;可用于没有参数的对象或参数。
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("æåøåæå"))
基于 angular's sanitize ...(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, '<');
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, '&').
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, '<').
replace(/>/g, '>');
}
export default {encode,decode};
afaik在javascript中没有任何直接的HTML Encode / Decode方法。
但是,你可以做的是使用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或任何东西;它只是告诉DOM设置value
属性(或属性;不确定)。无论哪种方式,DOM都会为您处理任何编码问题。除非您使用document.write
或eval
做一些奇怪的事情,否则HTML编码将是有效透明的。
如果你正在谈论生成一个新的文本框来保存结果......它仍然很容易。只需将HTML的静态部分传递给jQuery,然后在它返回给你的对象上设置其余的属性/属性。
$box = $('<input type="text" name="whatever">').val($('#hiddenId').val());
我有类似的问题并使用JavaScript中的函数encodeURIComponent
解决它( documentation )
例如,在您的情况下,如果您使用:
<input id='hiddenId' type='hidden' value='chalk & cheese' />
和
encodeURIComponent($('#hiddenId').attr('value'))
你会得到chalk%20%26%20cheese
。甚至保留空间。
在我的情况下,我必须编码一个反斜杠,这段代码完美无缺
encodeURIComponent('name/surname')
我得到name%2Fsurname
我的纯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;
}
如果你想使用jQuery。我发现了这个:
http://www.jquerysdk.com/api/jQuery.htmlspecialchars
(jQuery SDK提供的jquery.string插件的一部分)
Prototype的问题我认为它在JavaScript中扩展了基础对象,并且与您可能使用的任何jQuery不兼容。当然,如果你已经在使用Prototype而不是jQuery,那就不会有问题了。
编辑:还有这个,它是Prototype的jQuery字符串实用程序的一个端口:
var htmlEnDeCode = (function() {
var charToEntityRegex,
entityToCharRegex,
charToEntity,
entityToChar;
function resetCharacterEntities() {
charToEntity = {};
entityToChar = {};
// add the default set
addCharacterEntities({
'&' : '&',
'>' : '>',
'<' : '<',
'"' : '"',
''' : "'"
});
}
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, '&')
.replace(/"/g, '"')
.replace(/'/g, ''')
.replace(/</g, '<')
.replace(/>/g, '>');
}
var aString = '<script>alert("I hack your site")</script>';
console.log(aString.htmlEncode());
</script>
将输出:<script>alert("I hack your site")</script>
.htmlEncode()将在所有字符串上可访问。
HtmlEncodes给定值
var htmlEncodeContainer = $('<div />');
function htmlEncode(value) {
if (value) {
return htmlEncodeContainer.text(value).html();
} else {
return '';
}
}
我在Domain \ User字符串中遇到了反斜杠的一些问题。
我把这个添加到Anentropic回答中的其他逃脱
.replace(/\\/g, '\')
我在这里找到的: 如何在JavaScript中转义反斜杠?
这里有一点模仿Microsoft的ASP中的Server.HTMLEncode
函数,用纯JavaScript编写:
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范围之外的任何字符。
在prototype.js
中挑选escapeHTML()
正在做的事情
添加此脚本可帮助您转义HTML:
String.prototype.escapeHTML = function() {
return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>')
}
现在您可以在脚本中的字符串上调用escapeHTML方法,例如:
var escapedString = "<h1>this is HTML</h1>".escapeHTML();
// gives: "<h1>this is HTML</h1>"
希望它能帮助任何寻找简单解决方案的人,而不必包含整个prototype.js
在这里使用其他一些答案我创建了一个版本,可以替换一次传递中的所有相关字符,而不管不同编码字符的数量(只有一次调用replace()
),因此对于较大的字符串会更快。
它不依赖于DOM API存在或其他库。
window.encodeHTML = (function() {
function escapeRegex(s) {
return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
}
var encodings = {
'&' : '&',
'"' : '"',
'\'' : ''',
'<' : '<',
'>' : '>',
'\\' : '/'
};
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('<>&"\'')
获得<>&"'
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);