在表单和链接中使用 $_SERVER['REQUEST_URI'] 或 $_SERVER['PHP_SELF'] 的风险

5

在表单的操作中或链接的href中使用$_SERVER['REQUEST_URI']$_SERVER['PHP_SELF']是否存在风险?

如果存在风险,有什么方法可以减轻风险?

6个回答

4
您在www.example.com/form.php上创建一个表单,一年后,您忘记了URL仅抓取页面加载的任何URL。
在某个时候,让我们假设您已经添加了“删除所有内容”的全局选项作为完全不同(略微奇怪)请求的一部分。
现在,有人向您发送了此链接:www.example.com/form.php?delete_everything=true。由于您只是获取该URL并将其设置为操作,因此现在该操作是您表单上的操作。哎呀。XSS攻击基本上以这种方式工作。
始终假定您的代码将以您最初编写它时没有预料到的方式被使用(即使是您自己,尤其是黑客)。
如何解决?硬编码URL!您可以包含一个返回URL的函数。实际上,这就是Symfony或CodeIgniter等框架解决它的方式。

谢谢Blowski。硬编码的问题不在于URL,而在于URL中的数据。例如,我的URL是mysite.com?id=123,其中123带来了特殊的数据。无法硬编码每个id。 - user1032531
此外,如果用户只是在其客户端浏览器中输入www.example.com/form.php?delete_everything=true,是否会产生相同的效果?这如何处理XSS? - user1032531
在URL参数的情况下,您可以执行类似于action="www.example.com/form.php?id=<?php echo htmlspecialchars($_GET['id']); ?>"的操作。至于delete_everything=true-这是一个非常简单的例子(拥有这样的参数的疯狂想法),但是想象一下只有管理员才能传递该参数-没有问题,对吧?但是有一天,有人向管理员发送了包含该参数的电子邮件,他有点匆忙,点击了URL,提交了表单... - Dan Blows
有多种方式,但最常见的是社交工程。想象一下公司中有人的电子邮件被黑客攻击了。黑客使用该帐户向IT主管发送电子邮件,说“请填写这个表格”,并附上真实网站的链接 - 但恶意参数已添加到URL的末尾。现在,当IT主管提交表单时,它会将参数传递给后端,并造成损害。这里的重点是,它增加了很大的风险,而获得的好处却很少 - 编写一个构建URL的函数诚实地不需要花费很长时间。 - Dan Blows
@user1032531 说实话,你可以这样做,它将防范99%的可能攻击。但是,“深度防御”是指以多种方式保护自己(包括防御未知的未知因素)。例如,如果您的Web服务器存在漏洞,使得某人可以更改$_SERVER['PHP_SELF']值为www.nastysite.com/form.php,那么htmlentities()就无法保护您了。关于URL - 可以参考http://shiflett.org/blog/2005/feb/more-on-filtering-input-and-escaping-output#comment-7及其相关文章。 - Dan Blows
显示剩余2条评论

3
这是因为$_SERVER['PHP_SELF']$_SERVER['REQUEST_URI']可以以一种方式被操纵,如果你没有适当地转义它,它就可以用于XSS攻击。这很大程度上是由于这样的URL可以正常工作的事实造成的:
/path/to/index.php/" onmouseover="alert('hi')

让我们使用这段代码:

<form action="<?php echo $_SERVER['PHP_SELF']; ?>">
...
</form>

它调用了/path/to/index.php,也就是SCRIPT_NAME,但当你仅仅使用echo $_SERVER['PHP_SELF']时,它会破坏你预期的HTML。
<form action="/path/to/index.php/" onmouseover="alert('hi')">
...
</form>

解决方案

在许多情况下,使用<form action="">就足以使表单提交到当前脚本。否则,如果你知道脚本的名称叫"bla.php",那么设置action="bla.php"


如何在XSS攻击中使用它?我可以理解某人可能会更改它以适应他们的客户端电脑,但对其他人来说不行。您建议如何转义它?使用esc_url()函数吗? - user1032531
@user1032531 你考虑把这些链接放在许多人经常访问的论坛里吗? - Ja͢ck
你好,杰克。我已经读了你的帖子20遍,但仍然不理解。如果有其他线索,将不胜感激。 - user1032531
好的,也许我明白了。坏人在论坛上添加一个链接或者其他什么东西。好人点击该链接,URL中包含一些JS代码,会被执行。但是与表格有何关联还不太清楚。 - user1032531
@user1032531 不仅与表格有关,还可以应用于任何具有这些变量的未经审查值的东西。 - Ja͢ck

3

$_SERVER容易受到XSS攻击,使用前应该使用htmlspecialchars()进行清理。

以下是一个注入示例:

   <form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>"></form>

现在使用注入调用以下表单: http://www.example.com/form.php/%22%3E%3Cscript%3Ealert('xss attack')%3C/script%3E%3Cbr%20class=%22irrelevant
始终记得清理输入数据...一定要清理!

1
谢谢Joe,但这只会影响访问该URL的客户端个人,对其他人有什么影响吗? - user1032531
这可能是一个愚蠢的问题,但为什么在我所有的测试中,我都遇到了403错误,页面甚至没有加载? - user3292788

2

我知道这是一个相当古老的帖子,但这也是我一段时间以来一直在努力解决的问题。现在我所做的是:

$php_self = filter_input(INPUT_SERVER, 'PHP_SELF', 522);
define('PHP_SELF', $php_self);

通过这个方法,你可以安全地使用常量PHP_SELF作为表单操作。这段代码的作用是将超级全局变量 $_SERVER['PHP_SELF'] 通过过滤器运行,并将结果分配给变量 $php_self。编号522指的是 FILTER_SANITIZE_FULL_SPECIAL_CHARS,它可以防止有人注入 JavaScript 等内容。

你可以通过以下代码查看可用的过滤器:

<table>
<tr><td>Filter Name</td><td>Filter ID</td></tr>
<?php
foreach(filter_list() as $id =>$filter)
{
  echo '<tr><td>'.$filter.'</td><td>'.filter_id($filter).'</td></tr>'."n";
}
?>
</table>

同样的原则可以应用于大多数,如果不是所有的超级全局 $_SERVER 变量。
以下是我喜欢玩的一些变量:
# FILTER_SANITIZE_STRING or _STRIPPED
$server_http_xrw = filter_input(INPUT_SERVER, 'HTTP_X_REQUESTED_WITH', 513);
# FULL_SPECIAL_CHARS
$server_request_method = filter_input(INPUT_SERVER, 'REQUEST_METHOD', 522);
$http_encoding = filter_input(INPUT_SERVER, 'HTTP_ACCEPT_ENCODING', 522);

因此,通过利用PHP现在内置的过滤器,我们可以使用$_SERVER变量而不必太担心。

我希望这能帮助那些寻找答案的人。


这个老问题的新方法非常出色。 - a coder

0

-1

不,任何人都可以使用类似Firebug的工具更改链接的href。当然,确保您不在该链接中放置任何敏感数据。

始终确保正确验证和解析您接收到的用户数据。


谢谢Bart,对于表单操作也是如此,对吗? - user1032531
是的。(尽管我不知道为什么我的回答被踩了...) - Bart Friederichs
@BartFriederichs 我给你的帖子点了踩。虽然任何人都可以更改href,但如果它是硬编码的,它将始终按照开发人员想要的方式加载。通过获取$_SERVER[]变量,您会暴露自己受到攻击的风险。因此,这是相当危险的,应该是最后的选择。 - Dan Blows
@Blowski 谢谢。我得重新学习一下 XSS 攻击。 - Bart Friederichs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接