我如何防止XSS(跨站点脚本)只使用HTML和PHP?

关于这个主题,我已经看到了许多其他的帖子,但是我还没有找到一篇文章能够清楚而简洁地说明如何实际防止XSS。


当前回答

基本上,当您想要向浏览器输出来自用户输入的内容时,就需要使用htmlspecialchars()函数。

使用这个函数的正确方法是这样的:

echo htmlspecialchars($string, ENT_QUOTES, 'UTF-8');

谷歌Code University也有这些非常有教育意义的Web安全视频:

如何打破网络软件-看看安全漏洞 网络软件 关于安全,每个工程师都需要知道什么 以及在哪里学习

其他回答

最重要的步骤之一是在用户输入被处理和/或呈现回浏览器之前对其进行消毒。PHP有一些可以使用的“过滤器”函数。

XSS攻击的形式通常是向用户插入一些包含恶意意图的场外javascript的链接。点击这里阅读更多信息。

你还需要测试你的网站——我可以推荐Firefox插件[XSS Me]。看起来简单XSS是现在要走的路。

基本上,当您想要向浏览器输出来自用户输入的内容时,就需要使用htmlspecialchars()函数。

使用这个函数的正确方法是这样的:

echo htmlspecialchars($string, ENT_QUOTES, 'UTF-8');

谷歌Code University也有这些非常有教育意义的Web安全视频:

如何打破网络软件-看看安全漏洞 网络软件 关于安全,每个工程师都需要知道什么 以及在哪里学习

按偏好顺序排列:

If you are using a templating engine (e.g. Twig, Smarty, Blade), check that it offers context-sensitive escaping. I know from experience that Twig does. {{ var|e('html_attr') }} If you want to allow HTML, use HTML Purifier. Even if you think you only accept Markdown or ReStructuredText, you still want to purify the HTML these markup languages output. Otherwise, use htmlentities($var, ENT_QUOTES | ENT_HTML5, $charset) and make sure the rest of your document uses the same character set as $charset. In most cases, 'UTF-8' is the desired character set.

另外,确保在输出上转义,而不是在输入上转义。

<?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('#([a-z]*)[\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('#([a-z]*)[\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('#([a-z]*)[\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;
}

你也可以通过header(…)设置一些XSS相关的HTTP响应头

X-XSS-Protection”1;模式=块”

可以肯定的是,浏览器XSS保护模式是启用的。

Content-Security-Policy "default-src 'self';……”

启用浏览器端内容安全性。有关内容安全策略(CSP)的详细信息,请参阅:http://content-security-policy.com/ 特别是设置CSP来阻止内联脚本和外部脚本源有助于对抗XSS。

关于你的web应用程序安全性的一堆有用的HTTP响应头,请查看OWASP: https://www.owasp.org/index.php/List_of_useful_HTTP_headers