PHP 跨站脚本(XSS)
示例
问题
跨站点脚本是Web客户端意外执行的远程代码。如果任何Web应用程序从用户那里获取输入并将其直接输出到网页上,则可能会将其自身暴露给XSS。如果输入包括HTML或JavaScript,则Web客户端呈现此内容时可以执行远程代码。
例如,如果第三方方包含一个JavaScript文件:
// http://example.com/runme.js document.write("I'm running");
PHP应用程序直接输出传递给它的字符串:
<?php echo '<div>' . $_GET['input'] . '</div>';
如果包含未经检查的GET参数<scriptsrc="http://example.com/runme.js"></script>,则PHP脚本的输出为:
<div><script xx_src="http://example.com/runme.js"></script></div>
第三方JavaScript将运行,并且用户将在网页上看到“我正在运行”。
解
通常,永远不要信任来自客户端的输入。每个GET,POST和cookie值都可以是任何值,因此应进行验证。输出这些值中的任何一个时,请对其进行转义,以便不会以意外的方式对其进行求值。
请记住,即使在最简单的应用程序中,数据也可以移动,并且很难跟踪所有源。因此,最佳做法是始终不输出。
PHP提供了几种根据上下文对输出进行转义的方法。
过滤功能
PHP过滤器功能允许以多种方式对php脚本的输入数据进行清理或验证。当保存或输出客户端输入时,它们很有用。
HTML编码
htmlspecialchars会将所有“HTML特殊字符”转换为它们的HTML编码,这意味着它们将不被视为标准HTML。要使用此方法修复前面的示例:
<?php echo '<div>' . htmlspecialchars($_GET['input']) . '</div>'; //要么 echo '<div>' . filter_input(INPUT_GET, 'input', FILTER_SANITIZE_SPECIAL_CHARS) . '</div>';
将输出:
<div><script xx_src="http://example.com/runme.js"></script></div>
<div>标签内部的所有内容都不会被浏览器解释为JavaScript标签,而是解释为简单的文本节点。用户将安全地看到:
<script xx_src="http://example.com/runme.js"></script>
URL编码
输出动态生成的URL时,PHP提供了urlencode安全输出有效URL的功能。因此,例如,如果用户能够输入成为另一个GET参数一部分的数据:
<?php $input = urlencode($_GET['input']); //要么 $input = filter_input(INPUT_GET, 'input', FILTER_SANITIZE_URL); echo '<a href="http://example.com/page?input="' . $input . '">Link</a>';
任何恶意输入都将转换为编码的URL参数。
使用专用的外部库或OWASPAntiSamy列表
有时您会想要发送HTML或其他类型的代码输入。您将需要维护一个授权词列表(白名单)和未授权词列表(黑名单)。
您可以从OWASPAntiSamy网站上下载可用的标准列表。每个列表都适合特定类型的交互(ebayapi,tinyMCE等)。它是开源的。
现有的库可用来过滤HTML并在一般情况下防止XSS攻击,并且至少可以很容易地执行AntiSamy列表。例如,您有HTMLPurifier