这种创造性的输入净化方式可能会面临什么样的安全漏洞?(如有)


What kind of security loopholes could this creative way of sanitizing input, possibly face? (if any)

清除输入的标准方法是使用等命令

$url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%@$'|*''()''x80-''xff]|i', '', $url);

$strip = array('%0d', '%0a', '%0D', '%0A');

preg_replace("/[^A-Za-z0-9 ]/", '', $string);

echo htmlentities($str);

然而,当我的用户能够在他们的输入、评论/用户名等中使用括号、括号、引号等漂亮的东西时,我喜欢。由于HTML将(之类的代码呈现为(之类的符号,所以我希望使用这种替代方法来净化它们的输入。

在我开始为可能有害的角色(如(;<)编写一个函数之前(所以像偷偷摸摸的eval()<text/javascript>这样的注射是不起作用的),我试着搜索以前人们尝试过这种消毒的情况。

我没有发现

这让我觉得,在我的"创造性"消毒方法中,我一定明显忽略了一些令人难以置信的明显安全缺陷。

  1. 我不会将此函数用作保护mySQL数据库的主要方法。我有新的mysqli课程。在输入&不过,查询似乎是个不错的主意
  2. 我正在使用一个完全不同的函数来清理URL。这些需要一种不同的方法
  3. 不过,此函数将用于在页面上显示用户输入

所以。。。。我可能错过了什么?我知道这个想法肯定有问题,因为没有其他人使用它,对吧?!有可能"重新渲染渲染的文本"或其他可怕而明显的东西吗?到目前为止,我的小功能:

  • 接受meep';) drop tablealert(eval('document.body.inne' + 'rHTML'));

    function santitize_data($data)    {
    //explode the string
    //do a replacement for each character separately. Only do one replacement.
    //dont do it with preg_replace because that function searches through a string in multiple passes 
    //and replaces already-replaced characters, resulting in horrific mishmash.
    //put it back together with + signs iterating through array variables   
    $patterns = array();
    $patterns[0] = "'";
    $patterns[1] = '"';
    $patterns[2] = '!';
    $patterns[3] = '''';
    $patterns[4] = '#';
    $patterns[5] = '%';
    $patterns[6] = '&';
    $patterns[7] = '$';
    $patterns[8] = '(';
    $patterns[9] = ')';
    $patterns[10] = '/';
    $patterns[11] = ':';
    $patterns[12] = ';';
    $patterns[13] = '|';
    $patterns[14] = '<';
    $patterns[15] = '>';
    $patterns[16] = '{';
    $patterns[17] = '}';
    $replacements = array();
    $replacements[0] = '&#39;';
    $replacements[1] = '&#34;';
    $replacements[2] = '&#33';
    $replacements[3] = '&#92;';
    $replacements[4] = '&#35;';
    $replacements[5] = '&#37;';
    $replacements[6] = '&#38;';
    $replacements[7] = '&#36;';
    $replacements[8] = '&#40;';
    $replacements[9] = '&#41;';
    $replacements[10] = '&#47;';
    $replacements[11] = '&#58;';
    $replacements[12] = '&#59;';
    $replacements[13] = '&#124;';
    $replacements[14] = '&lt;';
    $replacements[15] = '&gt;';
    $replacements[16] = '&#123;';
    $replacements[17] = '&#125;';
    $split_data = str_split($data);
    foreach ($split_data as &$value) {
        for ($i=0; $i<17; $i++){
            //testing
            //echo '<br> i='.$i.' value='.$value.' patterns[i]='.$patterns[$i].' replacements[i]='.$replacements[$i].'<br>';
            if ($value == $patterns[$i]) { 
                $value = $replacements[$i];
                $i=17;    }    }    }
    unset($value); // break the reference with the last element
    $data = implode($split_data);
    //a bit of commented out code .. was using what seemed more logical before ... preg_replace .. but it parses the string in multiple passes ):
    //$data = preg_replace($patterns, $replacements, $data);
    return $data;
    } //---END function definition of santitize_data
    
  • 输出结果字符串,如meep&#39;&#59;&#41; drop tablealert&#40;eval&#40;&#39;document.body.inne&#39; + &#39;rHTML&#39;&#41;&#41;&#59;

  • 并且用户看到这些在浏览器中呈现的东西,比如CCD_ 17和alert(eval('document.body.inne' + 'rHTML'));

在不分析代码的情况下,我可以告诉您,您很可能忽略了攻击者可以用来注入自己代码的东西。

这里的主要威胁是XSS——不需要"清理"就可以将数据插入数据库。您可以使用参数化查询,也可以正确编码数据库查询语言在进入数据库时赋予特殊含义的字符(例如'字符)。XSS通常是通过在输出点进行编码来处理的,但是,如果你想允许富文本,那么你需要采取一种不同的方法,我相信这就是你希望在这里实现的。

请记住,没有一个神奇的函数可以以通用的方式净化输入——这在很大程度上取决于它在该上下文中如何以及在哪里被用来确定它是否安全。(添加了这一点,所以如果有人搜索并找到了这个答案,那么他们就会跟上速度——不过我想你已经掌握了。)

复杂性是安全的主要敌人。如果你不能确定你的代码是否安全,那就太复杂了,一个有足够动机、有足够时间的攻击者会找到绕过你的清理方法的方法。

对此你能做些什么

如果您想允许用户输入富文本,您可以允许BBCode允许用户通过自己的转换功能插入有限、安全的HTML子集,也可以允许HTML输入并通过久经考验的解决方案(如HTML净化器)运行内容。现在,HTML净化器不会是完美的,我相信在未来的某个时候会发现(另一个)缺陷。

如何防范这种情况

如果您在网站上实施内容安全策略,这将阻止任何成功注入的脚本代码在浏览器中执行。请参阅此处了解CSP的当前浏览器支持。不要只想使用其中一种方法——一个好的安全模型具有分层安全性,因此如果一个控件被绕过,另一个控件就可以捕获它

谷歌现在已经在Gmail中实现了CSP,以确保收到的任何HTML电子邮件都不会试图发动XSS攻击。