如何防止HTML / PHP的XSS?
如何防止使用HTML和PHP的XSS(跨站点脚本)?
我在这个主题上看到了很多其他的post,但是我还没有find一篇清楚而简洁的文章来说明如何实际阻止XSS。
基本上你需要使用函数htmlspecialchars()
只要你想输出的东西来自用户input的浏览器。
使用这个函数的正确方法是这样的:
echo htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
谷歌代码大学也有networking安全这些非常教育性的video:
-
如何打破networking软件 – 看看networking软件的安全漏洞
-
每个工程师都需要了解安全性以及在哪里学习
我最喜欢的OWASP参考资料之一是跨站脚本解释,因为虽然有大量的XSS攻击媒介,但下面的几条规则可以大大地防御它们的大部分!
这是PHP安全备忘单
最重要的步骤之一是在处理和/或渲染回浏览器之前清理任何用户input。 PHP有一些可以使用的“ filter ”function。
XSS攻击通常具有的forms是插入一个链接到一些包含恶意用户的异地javascript。 在这里阅读更多关于它。
你也想testing你的网站 – 我可以推荐Firefox插件XSS Me 。
按照优先顺序:
- 如果您正在使用模板引擎(例如Twig,Smarty,Blade),请检查它是否提供了上下文相关的转义。 我从经验中知道,枝杈是。
{{ var|e('html_attr') }}
- 如果您想要允许HTML,请使用HTML Purifier 。 即使你认为你只接受Markdown或ReStructuredText,你仍然想净化HTML这些标记语言输出。
- 否则,使用
htmlentities($var, ENT_QUOTES | ENT_HTML5, $charset)
,并确保文档的其余部分与$charset
使用相同的字符$charset
。 在大多数情况下,'UTF-8'
是所需的字符集。
此外,请确保您输出而不是input 。
<?php function xss_clean($data) { // Fix &entity\n; $data = str_replace(array('&','<','>'), array('&amp;','&lt;','&gt;'), $data); $data = preg_replace('/(&#*\w+)[\x00-\x20]+;/u', '$1;', $data); $data = preg_replace('/(&#x*[0-9A-F]+);*/iu', '$1;', $data); $data = html_entity_decode($data, ENT_COMPAT, 'UTF-8'); // Remove any attribute starting with "on" or xmlns $data = preg_replace('#(<[^>]+?[\x00-\x20"\'])(?:on|xmlns)[^>]*+>#iu', '$1>', $data); // Remove javascript: and vbscript: protocols $data = preg_replace('#([az]*)[\x00-\x20]*=[\x00-\x20]*([`\'"]*)[\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2nojavascript...', $data); $data = preg_replace('#([az]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2novbscript...', $data); $data = preg_replace('#([az]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*-moz-binding[\x00-\x20]*:#u', '$1=$2nomozbinding...', $data); // Only works in IE: <span style="width: expression(alert('Ping!'));"></span> $data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?expression[\x00-\x20]*\([^>]*+>#i', '$1>', $data); $data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?behaviour[\x00-\x20]*\([^>]*+>#i', '$1>', $data); $data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:*[^>]*+>#iu', '$1>', $data); // Remove namespaced elements (we do not need them) $data = preg_replace('#</*\w+:\w[^>]*+>#i', '', $data); do { // Remove really unwanted tags $old_data = $data; $data = preg_replace('#</*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|i(?:frame|layer)|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|title|xml)[^>]*+>#i', '', $data); } while ($old_data !== $data); // we are done... return $data; }
你也可以设置一些XSS相关的HTTP响应标题通过header(...)
X-XSS-Protection“1; mode = block”
可以肯定的是,浏览器XSS保护模式已启用。
Content-Security-Policy“default-src'self'; …”
以启用浏览器端的内容安全。 有关内容安全策略(CSP)的详细信息,请参阅以下内容: http : //content-security-policy.com/特别是设置CSP以阻止内联脚本和外部脚本源对XSS有帮助。
对于有关您webapp的安全性的一般有用的HTTP响应头文件,请看OWASP: https : //www.owasp.org/index.php/List_of_useful_HTTP_headers
在PHP
上使用htmlspecialchars
。 在HTML上尽量避免使用:
element.innerHTML = “…”; element.outerHTML = “…”; document.write(…); document.writeln(…);
var
由用户控制 。
也明显尝试避免eval(var)
,如果你必须使用它们中的任何一个,然后尝试JS转义他们, HTML转义他们,你可能不得不做一些,但基本上这应该是足够的。
将其作为脱机SO文档testing版的综合参考进行交叉发布。
问题
跨站点脚本是Web客户端无意执行的远程代码。 任何Web应用程序如果从用户处获得input并直接在网页上输出,则可能会将自身暴露给XSS。 如果input内容包含HTML或JavaScript,则当Web客户端呈现此内容时,可以执行远程代码。
例如,如果第三方包含JavaScript文件:
// http://example.com/runme.js document.write("I'm running");
一个PHP应用程序直接输出一个传递给它的string:
<?php echo '<div>' . $_GET['input'] . '</div>';
如果未经检查的GET参数包含<script src="http://example.com/runme.js"></script>
那么PHP脚本的输出将是:
<div><script src="http://example.com/runme.js"></script></div>
第三方JavaScript将运行,用户将在网页上看到“我正在运行”。
解
一般来说,不要相信来自客户端的input。 每个GET,POST和cookie值都可以是任何东西,因此应该进行validation。 当输出这些值时,将它们转义,这样就不会以意想不到的方式进行评估。
请记住,即使在最简单的应用程序中,数据也可以移动,并且很难跟踪所有的数据源。 因此总是逃避输出是一个最佳实践。
PHP提供了一些根据上下文来转义输出的方法。
过滤function
PHP的过滤函数允许input数据到PHP脚本进行消毒或validation在许多方面 。 在保存或输出客户端input时它们非常有用。
HTML编码
htmlspecialchars
将任何“HTML特殊字符”转换成他们的HTML编码,这意味着他们将不会被作为标准的HTML处理。 要使用此方法修复我们以前的示例:
<?php echo '<div>' . htmlspecialchars($_GET['input']) . '</div>'; // or echo '<div>' . filter_input(INPUT_GET, 'input', FILTER_SANITIZE_SPECIAL_CHARS) . '</div>';
输出:
<div><script src="http://example.com/runme.js"></script></div>
在<div>
标签内的所有内容都不会被浏览器解释为JavaScript标签,而是作为一个简单的文本节点。 用户将安全地看到:
<script src="http://example.com/runme.js"></script>
url编码
当输出dynamic生成的URL时,PHP提供了urlencode
函数来安全地输出有效的URL。 因此,例如,如果用户能够input成为另一个GET参数的一部分的数据:
<?php $input = urlencode($_GET['input']); // or $input = filter_input(INPUT_GET, 'input', FILTER_SANITIZE_URL); echo '<a href="http://example.com/page?input="' . $input . '">Link</a>';
任何恶意input将被转换为编码的URL参数。
使用专门的外部库或OWASP AntiSamy列表
有时你会想发送HTML或其他types的代码input。 您需要维护授权文字(白名单)和未经授权(黑名单)的清单。
您可以下载OWASP AntiSamy网站上的标准列表。 每个列表都适合特定types的交互(eBay api,tinyMCE等)。 它是开源的。
目前有一些库可以过滤HTML并防止一般情况下的XSS攻击,并且非常容易使用,至less可以执行AntiSamy列表。 例如你有HTML净化器