HTML属性编码和JavaScript字符串编码的本地JavaScript支持?

7
属性值需要进行编码。如果我要构建一个 jQuery 对象,代码如下: $('<div data-value="' + value + '">'); 实际上,value 必须像这样进行属性编码: $('<div data-value="' + HtmlAttributeEncode(value) + '">'); 我找不到这样的原生函数。有人认为只需将双引号替换为&quot;即可,但 Microsoft 的 HttpEncoder.HtmlAttributeEncode 方法会对这四个字符& < " '进行编码。我在此处看到了一些实现,例如 quoteattr : https://dev59.com/_Wsz5IYBdhLWcg3wpZhF#9756789 ,但它效率非常低,调用替换来多次迭代字符串。同样,我需要一个原生函数来对 JavaScript 字符串进行编码(例如 $('<div onclick="var s =\'' + HtmlAttributeEncode(JavaScriptStringEncode(value)) + '\';alert(s);"></div>)。appendTo(body); << 这只是一个为了说明而虚构的例子)。
是否有这种功能的原生等效物?
注意:请不要提到 escape (现在已弃用,改用 encodeURI encodeURIComponent ),它们都与属性编码无关。

抱歉,HTMLAttributeEncode 定义在哪里? - Michael
4个回答

3

不需要使用HTML转义字符,因为您可以使用DOM方法(或jQuery的封装)构建元素,这样就可以避免使用HTML转义字符了,因为您正在处理DOM而不是HTML。

$('<div />', { "data-value" : value });

或者

var div = document.createElement('div');
div.setAttribute('data-value', value);

如果您真的想获取转义后的HTML,可以使用DOM并从中生成HTML:
var html = $('<div />').append(
    $('<div />', { "data-value" : value })
).html();

这样做就违背了使用JQuery从字符串构建复杂嵌套元素(如模态对话框)的目的,例如($('<div class="modal fade" id="' + HtmlAttributeEncode(id) + '" role="dialog"><div class="modal-dialog"><div class="modal-content"></div></div></div>');作为生成此类对话框的函数的一部分。如果我不能在字符串中编码变量,那么我必须通过低效的“查找”调用和设置属性方法来单独定位生成的元素。我非常清楚“替代方案”,我想要的是本地功能,而不是“不要这样做”的答案。 - Triynko
1
这并不是一件坏事。将字符串拼接在一起是生成任何数据格式最容易出错和难以调试的方式。http://jsbin.com/golahutasa/1/edit?html,js,output 更易于维护和调试。 - Quentin
除了我在上一个代码示例答案中指出的方法外,没有本地功能可用。 - Quentin
它似乎是如此基本的功能:“属性编码”或“字符串编码”,应该像URI编码一样具有本地支持。浏览器显然已经实现了这些方法,为什么不公开它们呢?这也没有涉及JavaScript字符串编码。人们炫耀JavaScript的原因之一是它能够以完全非面向对象的方式解析类似于eval的字符串。jsbin帖子与此大相径庭,而且更长。虽然我喜欢这段代码,但在更大的场景中,它可能会变得过于复杂。 - Triynko
1
无论如何,这是一个非常好的例子,展示了如何以高度面向对象的方式使用jQuery构建DOM结构,但这不是我正在寻找的原始本地字符串编码功能。我想象一些网络应用程序可能会出于不同原因生成HTML字符串,而我不得不去寻找一个库来执行这些操作...而浏览器已经实现了这种功能。这就像是重新发明轮子,更不用说从AS3转回JS退后了十年。 - Triynko
显示剩余2条评论

2

这是一个比较古老的问题,但我认为随着JavaScript模板能力的增强更加有趣:

html = `<table title="${ myTitleVar }"><thead><tr>
</tr></thead></table>`

不再存在错误的风险,使用数百个jquery函数拼接代码既不切实际又不可移植。

因此,有一个小技巧可以编码属性。应该能正常工作。我想确保myTitleVar中没有引号或其他无意义字符:

    var $h=$('<span>');
    function encodeAttr(t) {
        return $h.attr('title',t).prop('outerHTML').match(/title="(.*)"/)[1];
    }

    html = `<table title="${ encodeAttr(myTitleVar) }"><thead><tr>
       </tr></thead></table>`


我没有在所有浏览器中进行测试。有些浏览器可能使用'而不是"来生成html,这可能会使问题稍微复杂一些。

https://jsfiddle.net/p359ux01/


这似乎无法处理引号,例如对于myTitleVar ='"><iframe src="javascript:alert(\'XSS\');">.jpg',我无论是调用encodeAttr(myTitleVar)还是直接使用myTitleVar,都得到相同的结果。 - seanf
1
@seanf 你说得对。我不记得当时我是用这个做什么的,但它确实对某些事情起作用。我正在编辑以找到一个可行的解决方案。 - Garr Godfrey
问题要求使用本机Javascript,但似乎需要jQuery? - Michael
这句话与 OP 所要求的不同,而是表达他们想要的。从问题中可以明显看出他们正在使用 JQuery。 - Garr Godfrey

1

这里是一个纯JS版本(不使用jQuery),主要受Garr Godfrey的答案启发,基本上基于Quentin的答案。它应该可以处理一些浏览器出于某种原因选择在属性中使用单引号的情况。请自行承担风险,等等。

// Implementation:
/**
 * Encodes an HTML attribute using the browser's DOM methods
 */
function encodeAttr(text) {
  const elem = document.createElement('p');
  elem.setAttribute('title', text);
  const elemHtml = elem.outerHTML; // <p title="encodedText"> or maybe <p title='encodedText'>
  // Find out whether the browser used single or double quotes before encodedText
  const quote = elemHtml[elemHtml.search(/['"]/)];
  // Split up the generated HTML using the quote character; take item 1
  return elemHtml.split(new RegExp(quote))[1];
}

// Demo:
const untrustedAttribute = '"><iframe src="javascript:alert(\'XSS\');">.jpg';
document.getElementById('results').innerHTML = 
  `<span title="${encodeAttr(untrustedAttribute)}"> My content </span>`;

https://jsfiddle.net/sys2061/vorm8Ldp/16/


-2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接