对Web失效的访问控制漏洞简单的分析及复现

漏洞原理介绍

大多数Web页面需要验证功能级别的访问权限。但是,服务器需要在每个功能被访问时在服务器端执行相同的访问控制检查。如果请求没有被验证,攻击者能够伪造请求以在未经适当授权时访问某些页面。

漏洞代码分析与实验演示

假如一个页面不添加任何访问限制,只是隐藏的话,那么只要在浏览器地址栏中输入该页面的地址,就能对其进行访问:

呐,这样就发现了大秘密了!真是刺激!
网页源码(没有任何限制,只要访问,就输出):

<?php
    echo "You find my secret!";
?>

代码修复

防止这种情况的发生,不止是隐藏页面地址,还要在页面处添加验证步奏。
添加了验证步奏后的页面源码,需要登录后访问:

<?php
error_reporting(0);
session_start();

$pass = [
    "zhangsan" => "zhang",
    "lisi" => "li",
    "wangwu" => "wang",
    "zhaoliu" => "zhao"
];

$users =[
    "zhangsan",
    "lisi",
    "wangwu",
    "zhaoliu"
];

$username = $_POST['username'];
$password = $_POST['password'];

if(in_array($username, $users)) {
    if($password===$pass[$username]) {
        $_SESSION['username'] = $username;
        echo "Welcome <mark>$username </mark>, you can see secret documents now.";
    }else{
        echo "Sorry, Username not match password.<br>Please check it carefully.";
    }
}else{
    echo "Sorry, you are unauthorized.";
}

?>

如图,是对添加了session验证的页面通过地址栏输入直接转跳访问时:

要想访问secre.php,先要通过登录验证,登录页面:

<?php

session_start();

$html = <<< EOD
<form action="secret.php" method="POST">

    <legend>
        用户登录
    </legend>
    <fieldset>
        <label for="username">Username:</label>
        <input type="text" name="username"><br/>
        <br>
        <label for="password">Password:</label>
        <input type="password" name="password"><br/>
        <br>
        <input type="submit" value="登录">
    </fieldset>

</form>
EOD;

// 输出表单
echo $html;

/**
 * 这是php的定界符
 * 在
 * <<<EOF 和 EOF; 之间的文本, 可以不用转义, 比如单引号和双引号
 * 一般用于输出长的html文本或者文本赋值
 * 例子:
 * $str = <<<EOF
 * 123123123
 * EOF;
 * 这里的EOF是一个标记,即是以EOF开头的必须以EOF结尾
 * 你可以换成其他字符也没问题
 * 还必须注意,EOF;这个结尾必须有分号,而且EOF必须顶格,之前没有任何字符,包括空格。
 **/
?>

当输入的用户信息不正确时:


回显:

当输入正确的用户名,密码:

回显:

成功转跳,访问到了secret.php,从而避免了无访问权限的用户对此网页进行访问,耶!

总结

  1. 对于这个漏洞的学习主要的难点是要对整个访问的流程有所了解,然后思考要在哪个层面上或者哪个操作前对其进行限制。再深入的考虑就是这种方法的可行度以及是否容易被绕过等等。
  2. 访问控制漏洞的解决方法还有很多,我这里只是列举了一种较为简单的通过session验证的方法,可能不尽完善,还有很多更为完备的方法需要学习和了解。