同步令牌模式防范CSRF跨站请求伪造攻击

什么是“跨渣请求伪造”呢?这是信息安全领域的一个名词,译自英文“Cross Site Request Forgery”。

百度百科上介绍的很简单却很明了,大家可以看一下,我这里配合一些代码稍微多说一点。

 

假设我们要在银行网站上给老妈转100块钱,毕竟毕业这么多年了也没给过家里钱(虽然你认为他们都在赚钱不需要你给,况且你自己现在赚钱刚好可以经济独立,不过实际上爹妈还是很希望你能支援家里的)。这个转账的HTTP请求类似于这样:

Html代码   收藏代码
  1. POST /transfer HTTP/1.1  
  2. Host: bank.example.com  
  3. Cookie: JSESSIONID=randomidDomain=bank.example.com; Secure; HttpOnly  
  4. Content-Type: application/x-www-form-urlencoded  
  5.   
  6. amount=100.00&routingNumber=1234&account=9876  

 你现在已经登录银行的网站了(你说你用的客户端?那当然没有这个危险性了,所以银行才都推荐U盾的),然后你新开了个标签页,进入一个“危机四伏”的网站(你傻啊,为什么要这样做。其实当别人没骗的时候我们都可以马后炮,但是没有足够的防范意识,任何时候我们被骗都是在鼓里)。

这个网站有一个链接,代码类似于这样:

Html代码   收藏代码
  1. <form action="https://bank.example.com/transfer" method="post">  
  2.   <input type="hidden"      name="amount"      value="100.00"/>  
  3.   <input type="hidden"      name="routingNumber"      value="evilsRoutingNumber"/>  
  4.   <input type="hidden"      name="account"      value="evilsAccountNumber"/>  
  5.   <input type="submit"      value="点我拿红包!"/>  
  6. </form>  

 除了一个“拿红包”的按钮之外,其他都是隐藏域。一看抢红包了,赶紧抢吧!这个表单提交后,和上面的请求是完全一样的。尽管这个网站没有你的cookie信息,可是你提交的时候cookie照样会被发送,所以它完全不需要拿到你的cookie。

你说:好像只要我足够小心,不去点击按钮就行了。当然不是,因为给你个按钮让你点是貌似愚蠢的做法,这个网站打开的同时,它的javascript代码说不定就不停的发生那个请求了。而你完全不知道。

 

为什么会这样?

因为接收action的服务器并不知道请求是跨站的,跨不跨站对于服务器来说没什么两样。

知道了这一点,我们的解决方法也就应运而生了:增加点东西让其他站点提供不了(因为只用cookie是不够的),这样服务器去验证这个域不就可以了吗。

一种方案是同步令牌模式。你的每一次请求,除了session数据外,都会提供服务器经response返回的随机串作为一个单独的http参数。提交后服务器会验证这个随机串。而其他网站是拿不到这个随机串的。

与之前的请求相比,只多了一个参数_csrf:

Html代码   收藏代码
  1. POST /transfer HTTP/1.1  
  2. Host: bank.example.com  
  3. Cookie: JSESSIONID=randomidDomain=bank.example.com; Secure; HttpOnly  
  4. Content-Type: application/x-www-form-urlencoded  
  5.   
  6. amount=100.00&routingNumber=1234&account=9876&_csrf=<secure-random>  

对于经过浏览器进行访问和发送接收请求的场景,防范CSRF攻击都有必要。 

 

 Spring Secure是怎么防范CSRF攻击呢?

首先,我们使用spring secure应该保证action的HTTP动词是合适的,不应该使用GET请求处理编辑性活动。使用POST要好得多。有的框架检测到token(就是上面提到的随机串)不合法马上就将用户登出要求重新登录。而Spring是产生一个403状态。

spring默认是开启 csrf防范的(如果使用命名空间需要开发者显示开启),如果想关闭,可以使用disable()方法:

Java代码   收藏代码
  1. @EnableWebSecurity  
  2. @Configuration  
  3. public class WebSecurityConfig extends  
  4.    WebSecurityConfigurerAdapter {  
  5.   @Override  
  6.   protected void configure(HttpSecurity http) throws Exception {  
  7.     http.csrf().disable();  
  8.   }  
  9. }  

 最后,要保证在除了GET外的请求中都包含_csrf域。不然,连登出都会失败(咦,登出不是GET吗?所以最好用POST)。

转载地址:http://somefuture.iteye.com/blog/2282894


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值