Java代码审计漏洞-CSRF跨站请求伪造

Java代码审计漏洞-CSRF跨站请求伪造

若要通过代码审计去挖掘 CSRF 漏洞,一般需要首先了解该开源程序的框架。CSRF 漏洞一般会在框架中存在防护方案,所以在审计CSRF漏洞时,首先要熟悉框架对CSRF的防护方案,若没有防护方案,则以该框架编写的所有Web程序都可能存在CSRF漏洞。若有防护方案,则可以首先去查看增删改请求中是否有token、formtoken、csrf-token等关键字,若有则可以进一步去通读该Web 程序对CSRF的防护源码,来判断其是否存在替换token值为自定义值并重复请求漏洞、重复使用 token 等漏洞。此外还要关注源程序是否对请求的Referer进行校验等。

框架Spring Security+Thymeleaf 中默认自动防御 csrf, 防御的原理就是生成 csrfToken 保存在 HttpSession 或者 Cookie 中。请求到来时,从请求中提取出来 csrfToken,和保存的 csrfToken 做比较,进而判断出当前请求是否合法。

Spring Security

@Configuration 
public class SecurityConfig extends WebSecurityConfigurerAdapter { 
    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
        http.authorizeRequests().anyRequest().authenticated() 
                .and() 
                .formLogin() 
                .and() 
                .csrf() 
                .disable(); 
    } 
} 

Thymeleaf

<body> 
<form action="/hello" method="post"> 
    <input type="hidden" th:value="${_csrf.token}" th:name="${_csrf.parameterName}"> 
    <input type="submit" value="hello"> 
</form> 
</body> 

Model

@GetMapping("/hello") 
public String hello2() { 
    return "hello"; 
} 

如果是前后端分离项目,Spring Security 也提供了解决方案。放在 Cookie 中返回前端

@Configuration 
public class SecurityConfig extends WebSecurityConfigurerAdapter { 
    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
        http.authorizeRequests().anyRequest().authenticated() 
                .and() 
                .formLogin() 
                .and() 
                .csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()); 
    } 
} 

框架没有自动防护,手写防护方案情况如下

Referer 过滤不严

1.从用户的请求头中取得 Referer 值
2.判断其是否为空。若为空,则跳转至首页;
3.若不为空,则进行下一步判断。
	判断Referer是否以 www.testdomain.com 开头,若不是,则跳转至首页;
	若是,则执行该操作请求。可以看到,这里逻辑判断的关键点在于第二步。
该判断仅仅判断请求 Referer 字段是否以www.testdomain.com开头,若我们构建一个二级域名为www.testdomain.com.hacker.com 的地址,则可能成功绕过该判断,从而进行 CSRF攻击。

token 可重用

判断 token 是否可用的核心代码

1.首先通过 generateToken() 方法生成一个属于该用户的 token,然后将其保存在服务端,并且将其镶嵌到 HTML页面中的<input>标签内。
2.当用户提交操作的时候,程序会比对该标签的 token 值是否等于服务端的 token 值,如果相等,则判断该操作是用户本人操作,而不是受到了CSRF 攻击。

其实这段源程序对于 CSRF 的防御机制是存在问题的。该段源程序在用户成功登录后,生成了唯一的令牌,直至该用户注销前,该 token 都是有效的。这就可能导致一个问题,如果这个 token 被盗用或者泄露,那么就可能导致CSRF 漏洞的发生。

漏洞防御

1)STP(Synchronizer Token Pattern,令牌同步模式),这种防御机制是当用户发送请求时,服务器端应用将token 嵌入HTML表格中,并发送给客户端。客户端提交HTML表格,会将令牌发送到服务端,令牌的验证是由服务端实行的。令牌可以通过任何方式生成,只要确保其随机性和唯一性。这样就能够确保攻击者发送请求的时候,由于没有该令牌而无法通过验证。

2)检查Referer字段。HTTP 头中有一个 Referer 字段,这个字段用以标明请求来源于哪个地址。在处理敏感数据请求时,一般情况下,Referer 字段应该与请求地址位于同一域名下。而如果是 CSRF 攻击传递来的请求,Referer 字段会是包含恶意攻击载荷的地址,通过这种判断能够识别出 CSRF 攻击。这种防御手段的关键点在于如何建立合适的校验机制。

3)添加校验token。CSRF 的本质是攻击者通过欺骗用户去访问自己设置的地址,所以如果在所有用户进行敏感操作时,要求用户浏览器提供未保存在Cookie中且攻击者无法伪造的数据作为校验,那么攻击者就无法再进行 CSRF 攻击。这种方式通常是在请求时增加一个加密的字符串token,当客户端提交请求时,这个字符串token也被一并提交上去以供校验。当用户进行正常的访问时,客户端的浏览器能够正确得到并传回这个字符串token

还有很多其他方式,比如验证码机制、自定义http请求头方式、Origin字段等,但是这些方法都存在各自的问题,如友好度差、存在机制绕过的可能等,因而只是作为辅助防御方式使用。

参考文章

java代码审计入门篇

https://github.com/JoyChou93/java-sec-code/wiki/CSRF

posted @ 2022-05-05 10:27  九天揽月丶  阅读(1157)  评论(0编辑  收藏  举报