如何防止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 。

按照优先顺序:

  1. 如果您正在使用模板引擎(例如Twig,Smarty,Blade),请检查它是否提供了上下文相关的转义。 我从经验中知道,枝杈是。 {{ var|e('html_attr') }}
  2. 如果您想要允许HTML,请使用HTML Purifier 。 即使你认为你只接受Markdown或ReStructuredText,你仍然想净化HTML这些标记语言输出。
  3. 否则,使用htmlentities($var, ENT_QUOTES | ENT_HTML5, $charset) ,并确保文档的其余部分与$charset使用相同的字符$charset 。 在大多数情况下, 'UTF-8'是所需的字符集。

此外,请确保您输出而不是input 。

 <?php function xss_clean($data) { // Fix &entity\n; $data = str_replace(array('&amp;','&lt;','&gt;'), array('&amp;amp;','&amp;lt;','&amp;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>&lt;script src=&quot;http://example.com/runme.js&quot;&gt;&lt;/script&gt;</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净化器