网页重定向到参数中给定的 URLredirect而不过滤它,如下所示:
$newURL=$_GET["redirect"];
header('Location: '.$newURL);
login.php?redirect=home.php
如果它回显了输入,我知道它可以执行 XSS 攻击,但是当它仅在标头方法中使用时我们可以注入代码吗?这是一个安全的脚本吗?
网页重定向到参数中给定的 URLredirect而不过滤它,如下所示:
$newURL=$_GET["redirect"];
header('Location: '.$newURL);
login.php?redirect=home.php
如果它回显了输入,我知道它可以执行 XSS 攻击,但是当它仅在标头方法中使用时我们可以注入代码吗?这是一个安全的脚本吗?
不,这是不安全的,不应该这样做。事实上,这是OWASP Top 10的最后一个:
A10。未经验证的重定向和转发
Web 应用程序经常将用户重定向和转发到其他页面和网站,并使用不受信任的数据来确定目标页面。如果没有适当的验证,攻击者可以将受害者重定向到网络钓鱼或恶意软件站点,或者使用转发来访问未经授权的页面。
攻击者可以制作一个 URL 以重定向到他们想要的任何页面,然后将其传播到各处:
http://trusted.com/index.php?redirect=http%3A%2F%2Fmalicious.com
通过对所有字符进行 URL 编码,恶意 URL 可能会被混淆以避免用户检测到,因此您会得到一个类似%68%74%74%70%3A%2F%2F%6D%61%6C%69%63%69%6F%75%73%2E%63%6F%6D.
现在,用户点击看起来像是指向您网站的普通安全链接的内容可能最终会出现在任何地方:
如果这是在用户登录后完成的,正如您在问题中所暗示的那样,这会更加危险,因为实际上在您的页面上输入凭据会增强用户对他实际上在您的网站上的信念。登录后提供“密码错误,重试”类型的页面非常容易。
正如 Steffen Ullrich 在他对这个问题的回答和我在对另一个问题的回答中已经说过的那样,在5.1.2之前的 PHP 版本上,这可以用于标头注入。
通常,解决方案是列入白名单。这是一个 PHP 示例:
$param = $_GET["redirect"];
$allowed = array(
"index" => "index.php",
"blog" => "blog/index.php",
// ...and so on...
);
$redirect = isset($allowed[$param]) ? $allowed[$param] : "index.php";
header('Location: '.$redirect);
如果您希望能够重定向到许多页面,这将是乏味的。根据您的 URL 的外观,您可以验证您自己网站的 URL。例如,如果它们在表单上,http://trutsted.com/?pageid=1234您只能接受分页以重定向到并验证它实际上是数字。
如果您只希望重定向链接在您自己的站点内工作,您可以检查请求的 HTTP 引用标题。如果您同时通过 HTTP 和 HTTPS 为您的网站提供服务,这可能会遇到一些问题,因为如果您从 HTTP 页面链接到 HTTPS 页面,则不会发送引用标头。
这是一些示例代码:
$headers = apache_request_headers();
$referer = isset($headers['referer']) ? parse_url($headers['referer'], PHP_HOST) : "";
if($referer == "trusted.com") {
//Do the redirect. If you want your code to be safe on old PHP versions,
//you will need to filter out newlines or just URL encode the URL.
}
else {
//Inform the user of the problem or just redirect to your index page.
}
当前版本的 PHP 检测并防止标头函数中的换行符注入,请参阅如何避免 HTTP 标头注入(换行符)。在旧版本的 pf PHP 中,您可能会执行类似的操作
login.php?redirect=%0D%0A%0D%0A<script>...
这会突破标题并导致
Location:
<script>...
然后你的脚本可以做任何它想做的事情,包括访问和转发会话 cookie 以进行会话劫持。
这并不意味着您的脚本对于当前的 PHP 是安全的。重定向到任意 URL 绝不是一个好主意,因此您应该将 newURL 限制为您希望重定向的 URL。
添加到其他人所说的话:
如果您有一组要重定向到的已知 URL(您可以映射到标识符),那么在“重定向”参数值中只允许已知标识符会更好。然后,您可以将标识符映射到您的安全、已知的 URL。
多亏了这种技术,“你所有的麻烦”都消失了。
当然,如果 URL 的值对于您的用户是 100% 任意的,或者如果您没有所有可能的 URL 的集合,那么这不适用。但是,如果您的 URL 对应于您可以控制的已知页面,那就去吧!
我能想到的第一个漏洞是将完整的 URL 作为参数传递,将用户重定向到站点的假副本(login.php?redirect=http://malicious.com)
除此之外,我确信有几种方法可以防止重定向发生并显示恶意 HTML/JavaScript。
作为一般规则,应清理任何URL 参数。