当在表单上接收用户输入时,我想检测“用户名”或“地址”等字段是否不包含在 XML(RSS 提要)或 (X)HTML(显示时)中具有特殊含义的标记。
那么,在 HTML 和 XML 上下文中,检测输入的输入是否不包含任何特殊字符的正确方法中,哪一个是正确的方法?
if (mb_strpos($data, '<') === FALSE AND mb_strpos($data, '>') === FALSE)
或
if (htmlspecialchars($data, ENT_NOQUOTES, 'UTF-8') === $data)
或
if (preg_match("/[^\p{L}\-.']/u", $text)) // problem: also caches symbols
我是否遗漏了其他任何东西,例如字节序列或其他获取标记标签的棘手方法,如“javascript:”?据我所知,所有XSS and CSFR attacks需要 <
或 >
围绕让浏览器执行代码的值(至少从 Internet Explorer 6 或更高版本开始)- 这是否正确?
我不是在寻找减少或过滤输入的东西。我只是想在 XML 或 HTML 上下文中使用时定位危险的字符序列。 (strip_tags()
非常不安全。正如手册所述,它不会检查格式错误的 HTML。)
更新
我想我需要澄清的是,有很多人误这个问题是关于通过“转义”或“过滤”危险字符的基本安全性的问题。这不是那个问题,给出的大多数简单答案无论如何都无法解决这个问题。
更新 2:示例
- 用户提交输入
-
if (mb_strpos($data, '<') === FALSE AND mb_strpos($data, '>') === FALSE)
- 我保存了
现在数据已在我的应用程序中,我用它做了两件事 - 1) 以类似 HTML 的格式显示 - 或 2) 在格式元素内显示以供编辑。
第一个在 XML 和 HTML 上下文中是安全的
<h2><?php print $input; ?></h2>'
<xml><item><?php print $input; ?></item></xml>
第二种形式比较危险,但应该还是安全的:
<input value="<?php print htmlspecialchars($input, ENT_QUOTES, 'UTF-8');?>">
更新 3:工作代码
您可以下载the gist I created并将代码作为文本或 HTML 响应运行以查看我在说什么。这个简单的检查通过了 http://ha.ckers.org XSS Cheat Sheet ,但我找不到任何成功的东西。 (我忽略了 Internet Explorer 6 及更低版本)。
我发起了另一项赏金事件,以奖励能够证明这种方法存在问题或实现过程中存在弱点的人。
更新 4:询问 DOM
这是我们要保护的 DOM - 那么为什么不直接询问呢? Timur's answer导致这个:
function not_markup($string)
{
libxml_use_internal_errors(true);
if ($xml = simplexml_load_string("<root>$string</root>"))
{
return $xml->children()->count() === 0;
}
}
if (not_markup($_POST['title'])) ...
最佳答案
我认为您不需要实现一个庞大的算法来检查字符串是否包含不安全的数据 - 过滤器和正则表达式可以完成工作。但是,如果您需要更复杂的检查,也许这会满足您的需求:
<?php
$strings = array();
$strings[] = <<<EOD
';alert(String.fromCharCode(88,83,83))//\';alert(String.fromCharCode(88,83,83))//";alert(String.fromCharCode(88,83,83))//\";alert(String.fromCharCode(88,83,83))//--></SCRIPT>">'><SCRIPT>alert(String.fromCharCode(88,83,83))</SCRIPT>
EOD;
$strings[] = <<<EOD
'';!--"<XSS>=&{()}
EOD;
$strings[] = <<<EOD
<SCRIPT SRC=http://ha.ckers.org/xss.js></SCRIPT>
EOD;
$strings[] = <<<EOD
This is a safe text
EOD;
$strings[] = <<<EOD
<IMG SRC="javascript:alert('XSS');">
EOD;
$strings[] = <<<EOD
<IMG SRC=javascript:alert('XSS')>
EOD;
$strings[] = <<<EOD
<IMG SRC=javascript:alert('XSS')>
EOD;
$strings[] = <<<EOD
perl -e 'print "<IMG SRC=java\0script:alert(\"XSS\")>";' > out
EOD;
$strings[] = <<<EOD
<SCRIPT/XSS SRC="http://ha.ckers.org/xss.js"></SCRIPT>
EOD;
$strings[] = <<<EOD
</TITLE><SCRIPT>alert("XSS");</SCRIPT>
EOD;
libxml_use_internal_errors(true);
$sourceXML = '<root><element>value</element></root>';
$sourceXMLDocument = simplexml_load_string($sourceXML);
$sourceCount = $sourceXMLDocument->children()->count();
foreach( $strings as $string ){
$unsafe = false;
$XML = '<root><element>'.$string.'</element></root>';
$XMLDocument = simplexml_load_string($XML);
if( $XMLDocument===false ){
$unsafe = true;
}else{
$count = $XMLDocument->children()->count();
if( $count!=$sourceCount ){
$unsafe = true;
}
}
echo ($unsafe?'Unsafe':'Safe').': <pre>'.htmlspecialchars($string,ENT_QUOTES,'utf-8').'</pre><br />'."\n";
}
?>
关于php - 检测字符串输入是否包含 HTML 的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8419038/