background image

php 通过语义 URL 防止网站被攻击

语义 URL 攻击

    好奇心是很多攻击者的主要动机,语义 URL 攻击就是一个很好的例子。此类攻击主要
包括对 URL 进行编辑以期发现一些有趣的事情。虽然对 GET 数据的操纵只是比对 POST 
数据稍为方便,但它的暴露性决定了它更为频繁的受攻击,特别是对于攻击的新手而言。
    大多数的漏洞是由于疏漏而产生的,而不是特别复杂的原因引起的。虽然很多有经验的
程序员能轻易地意识到上面所述的对 URL 的信任所带来的危险,但是常常要到别人指出
才恍然大悟。
    为了更好地演示语义 URL 攻击及漏洞是如何被疏忽的,以一个 Webmail 系统为例,该
系统主要功能是用户登录察看他们自己的邮件。任何基于用户登录的系统都需要一个密码
找回机制。通常的方法是询问一个攻击者不可能知道的问题(如你的计算机的品牌等,但
如果能让用户自己指定问题和答案更佳),如果问题回答正确,则把新的密码发送到注
册时指定的邮件地址。
    对于一个 Webmail 系统,可能不会在注册时指定邮件地址,因此正确回答问题的用户
会被提示提供一个邮件地址(在向该邮件地址发送新密码的同时,也可以收集备用邮件
地址信息)。下面的表单即用于询问一个新的邮件地址,同时他的帐户名称存在表单的一
个隐藏字段中:
<form action="reset.php" method="GET">
<input type="hidden" name="user" value="chris" />
<p>Please specify the email address where you want your new password sent:</p>
<input type="text" name="email" /><br />
<input type="submit" value="Send Password" />
</form>
可以看出,接收脚本 reset.php 会得到所有信息,包括重置哪个帐号的密码、并给出将新密
码发送到哪一个邮件地址。
如果一个用户能看到上面的表单(在回答正确问题后),你有理由认为他是 chris 帐号的
合法拥有者。如果他提供了 chris@example.org 作为备用邮件地址,在提交后他将进入下面
的 URL:
http://example.org/reset.php?user=chris&email=chris%40example.org
该 URL 出现在浏览器栏中,所以任何一位进行到这一步的用户都能够方便地看出其中的
user 和 mail 变量的作用。当意思到这一点后,这位用户就想到 php@example.org 是一个非
常酷的地址,于是他就会访问下面链接进行尝试:
http://example.org/reset.php?user=php&email=chris%40example.org
如果 reset.php 信任了用户提供的这些信息,这就是一个语义 URL 攻击漏洞。在此情况下,
系统将会为 php 帐号产生一个新密码并发送至 chris@example.org,这样 chris 成功地窃取
了 php 帐号。
如果使用 session 跟踪,可以很方便地避免上述情况的发生:
<?php
session_start();
$clean = array();
$email_pattern = '/^[^@s<&>]+@([-a-z0-9]+.)+[a-z]{2,}$/i';
if (preg_match($email_pattern, $_POST['email']))