在不过滤的情况下重定向到 URL 参数是否安全?

信息安全 php xss 注射 网址重定向
2021-08-19 16:35:24

网页重定向到参数中给定的 URLredirect而不过滤它,如下所示:

$newURL=$_GET["redirect"];
header('Location: '.$newURL);

login.php?redirect=home.php

如果它回显了输入,我知道它可以执行 XSS 攻击,但是当它仅在标头方法中使用时我们可以注入代码吗?这是一个安全的脚本吗?

4个回答

简短的回答

不,这是不安全的,不应该这样做。事实上,这是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.

现在,用户点击看起来像是指向您网站的普通安全链接的内容可能最终会出现在任何地方:

  • 在一个看起来和你一模一样的网站上,要求输入用户名和密码。繁荣,帐户被盗。
  • 一个通过下载驱动传播恶意软件的网站。您可以尝试声称这不是您的问题,因为从技术上讲,它不是您的网站传播它。我不确定受害者会同意。
  • 随便什么。您是否希望用户单击指向您网站的链接并最终访问非法或 NSFW 或 NSFL 内容?

如果这是在用户登录后完成的,正如您在问题中所暗示的那样,这会更加危险,因为实际上在您的页面上输入凭据会增强用户对他实际上在您的网站上的信念。登录后提供“密码错误,重试”类型的页面非常容易。

标头注入

正如 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.
}

更多阅读

  • OWASP关于未经验证的重定向的备忘单。(关于如何不在这里执行的示例之一几乎与您在问题中的执行方式相同。)
  • 特洛伊亨特在这个话题上有一篇很棒的文章。

当前版本的 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 参数。