2019-2-28 dvwa学习(4)--sql注入级别impossible

继续把dvwa环境安全级别调整为impossible
观察界面
在这里插入图片描述
看上去似乎和low级别没有大的区别,只是浏览器中get方法提交的参数多了一个。
impossible.php代码如下

 <?php

if( isset( $_GET[ 'Submit' ] ) ) {
    // Check Anti-CSRF token
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

    // Get input
    $id = $_GET[ 'id' ];

    // Was a number entered?
    if(is_numeric( $id )) {
        // Check the database
        $data = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' );
        $data->bindParam( ':id', $id, PDO::PARAM_INT );
        $data->execute();
        $row = $data->fetch();

        // Make sure only 1 result is returned
        if( $data->rowCount() == 1 ) {
            // Get values
            $first = $row[ 'first_name' ];
            $last  = $row[ 'last_name' ];

            // Feedback for end user
            echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
        }
    }
}

// Generate Anti-CSRF token
generateSessionToken();

?>

在impossible级别这个界面上如果尝试注入是不会成功的。因为这里增加了2个安全防范措施。

1.Check Anti-CSRF token
在impossible.php中有以下代码,是为了防止CSRF攻击。可以参考《Web安全之CSRF攻击

 // Check Anti-CSRF token
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

CSRF,Cross Site Request Forgery,中文是跨站点请求伪造。CSRF攻击者在用户已经登录目标网站之后,诱使用户访问一个攻击页面,利用目标网站对用户的信任,以用户身份在攻击页面对目标网站发起伪造用户操作的请求,达到攻击目的。
CSRF攻击是源于Web的隐式身份验证机制!Web的身份验证机制虽然可以保证一个请求是来自于某个用户的浏览器,但却无法保证该请求是用户批准发送的。
CSRF攻击的一般是由服务端解决。
应对CSRF的方法有

  • 尽量使用POST,限制GET
  • 浏览器Cookie策略
  • 加验证码
  • Referer Check ,例如:防止图片盗链
  • Anti CSRF Token

在上面代码中就是采用的最后一种。

那么什么是Token呢?
Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码。这样可以减轻服务器的压力,减少频繁的查询数据库。

使用Token有2种方式:

  1. 用设备号/设备mac地址作为Token
  2. 用session值作为Token用session值作为Token

Token的好处是服务端不需要存储相应信息。
大概的流程是这样的:

  1. 客户端使用用户名跟密码请求登录
  2. 服务端收到请求,去验证用户名与密码
  3. 验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
  4. 客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里
  5. 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
  6. 服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据

当然,如果Token被不怀好意的人从中间获取到该信息时,也容易被利用,非法获取数据。 想增强安全性,一般可以在服务端生成时配合时间戳,服务端在接收到client发来带token的信息时,先检测token的时间戳信息,如果该时间戳在超过某个时间点时,就认为过期,需要重新获取。

Token一般用在两个地方:

  1. 防止表单重复提交:服务器端第一次验证相同过后,会将session中的Token值更新。若用户重复提交,第二次的验证判断将失败,因为用户提交的表单中的Token没变,但服务器端session中Token已经改变了。
  2. anti csrf攻击(跨站点请求伪造):服务器端会对Token值进行验证,判断是否和session中的Token值相等。若相等,则可以证明请求有效,不是伪造的。

现在我们来看看代码里如何生成的。
在登录界面/var/www/html/login.php和本页面都能生成Token

**// Anti-CSRF
generateSessionToken();

这个函数在/var/www/html/dvwa/includes/dvwaPhpIds.inc.php中

function generateSessionToken() {  # Generate a brand new (CSRF) token
        if( isset( $_SESSION[ 'session_token' ] ) ) {
                destroySessionToken();
        }
        $_SESSION[ 'session_token' ] = md5( uniqid() );
}

验证就是在impossible.php中。
请注意:要避免"加token但不进行校验"的情况。在session中增加了token,但服务端没有对token进行验证,那根本起不到防范的作用。

我们可以尝试提交2次

http://192.168.99.100/vulnerabilities/sqli/index.php?id=1&Submit=Submit&user_token=9f874c66039244204e9951d4c7f7d551#
http://192.168.99.100/vulnerabilities/sqli/index.php?id=1&Submit=Submit&user_token=76f150ddea1eb5a7e670718f1f9f4d61#

可以发现浏览器的URL中2次的Token是不一样的。

2.sql预编译语句

观察以下代码,这个就是预编译。

$data = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' );

预编译语句的优势在于归纳为:一次编译、多次运行,省去了解析优化等过程。预编译语句能防止sql注入。
mysql4.1以后支持预编译。

在impossible.php中还限制了只允许返回一条数据。

if( $data->rowCount() == 1 )

猜你喜欢

转载自blog.csdn.net/weixin_42555985/article/details/88028776