在使用Javascript将其添加到DOM之前清理用户输入

I G*_*ICE 35 javascript xss escaping

我正在为我在空闲时间工作的聊天应用程序编写JS,我需要根据用户提交的数据更改HTML标识符.这通常是概念上不稳定的东西,我甚至都不会尝试它,但这次我不认为自己有很多选择.我需要做的是转义HTML id以确保它不允许XSS或破坏HTML.

这是代码:

var user_id = escape(id)
var txt = '<div class="chut">'+
            '<div class="log" id="chut_'+user_id+'"></div>'+
            '<textarea id="chut_'+user_id+'_msg"></textarea>'+
            '<label for="chut_'+user_id+'_to">To:</label>'+
            '<input type="text" id="chut_'+user_id+'_to" value='+user_id+' readonly="readonly" />'+
            '<input type="submit" id="chut_'+user_id+'_send" value="Message"/>'+
          '</div>';
Run Code Online (Sandbox Code Playgroud)

逃避id避免上述任何问题的最佳方法是什么?正如你所看到的,现在我正在使用内置escape()函数,但我不确定它与其他替代品相比有多好.我主要习惯在输入文本节点之前清理输入,而不是id本身.

bob*_*nce 42

千万不要使用escape().这与HTML编码无关.它更像是URL编码,但它甚至都不正确.这是一种奇怪的非标准编码,只能在JavaScript中使用.

如果你想要一个HTML编码器,你必须自己编写,因为JavaScript没有给你一个.例如:

function encodeHTML(s) {
    return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/"/g, '&quot;');
}
Run Code Online (Sandbox Code Playgroud)

然而,虽然这足以将你user_id放在像这样的地方input value,但这还不够,id因为ID只能使用有限的字符选择.(而且%不在其中,所以escape()甚至encodeURIComponent()不好.)

您可以创建自己的编码方案,将任何字符放入ID中,例如:

function encodeID(s) {
    if (s==='') return '_';
    return s.replace(/[^a-zA-Z0-9.-]/g, function(match) {
        return '_'+match[0].charCodeAt(0).toString(16)+'_';
    });
}
Run Code Online (Sandbox Code Playgroud)

但如果同样user_id发生两次,你仍然会遇到问题.说实话,抛出HTML字符串的整个过程通常都是个坏主意.请改用DOM方法,并保留对每个元素的JavaScript引用,这样您就不必继续调用getElementById,也不必担心如何将任意字符串插入到ID中.

例如.:

function addChut(user_id) {
    var log= document.createElement('div');
    log.className= 'log';
    var textarea= document.createElement('textarea');
    var input= document.createElement('input');
    input.value= user_id;
    input.readonly= True;
    var button= document.createElement('input');
    button.type= 'button';
    button.value= 'Message';

    var chut= document.createElement('div');
    chut.className= 'chut';
    chut.appendChild(log);
    chut.appendChild(textarea);
    chut.appendChild(input);
    chut.appendChild(button);
    document.getElementById('chuts').appendChild(chut);

    button.onclick= function() {
        alert('Send '+textarea.value+' to '+user_id);
    };

    return chut;
}
Run Code Online (Sandbox Code Playgroud)

您还可以使用便捷函数或JS框架来减少create-set-appends调用的冗长度.

ETA:

我现在正在使用jQuery作为框架

好的,然后考虑jQuery 1.4创建快捷方式,例如:

var log= $('<div>', {className: 'log'});
var input= $('<input>', {readOnly: true, val: user_id});
...
Run Code Online (Sandbox Code Playgroud)

我现在遇到的问题是我使用JSONP向页面添加元素和事件,因此在显示消息之前我无法知道元素是否已经存在.

您可以user_id在JavaScript中查找元素节点(或包装器对象),以便将该信息保存在DOM本身中,其中可以进入的字符id受到限制.

var chut_lookup= {};
...

function getChut(user_id) {
    var key= '_map_'+user_id;
    if (key in chut_lookup)
        return chut_lookup[key];
    return chut_lookup[key]= addChut(user_id);
}
Run Code Online (Sandbox Code Playgroud)

(_map_前缀是因为JavaScript对象不能完全作为任意字符串的映射.空字符串和IE中的一些Object成员名称会混淆它.)


Sil*_*Imp 10

你也可以用这个:

function sanitize(string) {
  const map = {
      '&': '&amp;',
      '<': '&lt;',
      '>': '&gt;',
      '"': '&quot;',
      "'": '&#x27;',
      "/": '&#x2F;',
  };
  const reg = /[&<>"'/]/ig;
  return string.replace(reg, (match)=>(map[match]));
}
Run Code Online (Sandbox Code Playgroud)

OWASP文档建议maping:https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_prevention_Cheat_Sheet

  • @JohnBalvinArias 你可以将它添加到上面的例子中,它的``` (4认同)

aaa*_*aaa 9

您可以使用一个简单的正则表达式断言id只包含允许的字符,如下所示:

if(id.match(/^[0-9a-zA-Z]{1,16}$/)){
    //The id is fine
}
else{
    //The id is illegal
}
Run Code Online (Sandbox Code Playgroud)

我的示例仅允许使用字母数字字符和长度为1到16的字符串,您应该更改它以匹配您使用的ID类型.

顺便说一下,在第6行,value属性缺少一对引号,当你引用两个级别时,这是一个容易犯的错误.

我无法看到您的实际数据流,具体取决于上下文可能根本不需要此检查,或者可能还不够.为了进行适当的安全审查,我们需要更多信息.

一般来说,关于内置的逃生或消毒功能,不要盲目相信它们.你需要确切地知道他们做了什么,你需要确定这实际上是你需要的.如果它不是你需要的,你自己的代码,大多数时候像我给你的那个简单的白名单正则表达式工作得很好.