zoukankan      html  css  js  c++  java
  • 跨站请求伪造攻击 CSRF

    摘录:

    1.跨站点请求伪造

    首先,什么是跨站点请求伪造?

    跨站点请求伪造-CSRF(Cross Site Request Forgery):是一种网络攻击方式。

    说的白话一点就是,别的站点伪造你的请求,最可怕的是你还没有察觉并且接收了。听起来确实比较危险,下面有个经典的实例,了解一下跨站点请求伪造到底是怎么是实现的,知己知彼。

    受害者:Bob 黑客:Mal 银行:bank bob在银行有一笔存款,可以通过请求http://bank.example/withdraw?account=bob&amount=1000000&for=bob2把钱转到bob2下。通常情况下,该请求到达网站后,服务器会验证请求是否来自一个合法的session,并且该session的用户Bob已登录。Mal在该银行也有账户,于是他伪造了一个地址http://bank.example/withdraw?account=bob&amount=1000000&for=mal,但是如果直接访问,服务器肯定会识别出当前登录用户是mal而不是Bob,不能接受请求。于是通过CSRF攻击方式,将此链接伪造在广告下,诱使Bob自己点这个链接,那么请求就会携带Bob浏览起的cookie一起发送到银行,而Bob同时又登录了银行或者刚刚登录不久session还没有过期,那服务器发现cookie中有Bob的登录信息,就接收了响应,攻击就成功了

    2.现在主要的几种防御CSRF的策略:

    1. 验证Referer:

    referer携带请求来源,从示例可以看出,受害者发送非法请求肯定不是在银行的界面,所以在服务器通过验证Referer是不是bank.example开始就可以了,这个方法简单粗暴。

    最简单的实现就是加个Filter:

    [java] view plain copy
     
    1. /** 
    2.  * 根据请求地址获取token-key 
    3.  */  
    4. public static String getTokenKey(HttpServletRequest request){  
    5.     String key = null;  
    6.         try {  
    7.             MessageDigest mDigest = MessageDigest.getInstance("MD5");//摘要算法可以自己选择  
    8.             byte[] result = mDigest.digest(request.getRequestURL().toString().getBytes());  
    9.             key = StringUtil.bytes2hex(result);  
    10.         } catch (NoSuchAlgorithmException e) {  
    11.            LOGGER.error("get token key failed",e);  
    12.         }   
    13.         return key  
    14. }  
    15.   
    16. /** 
    17.  * 获取token-value并存储在session中 
    18.  */  
    19. public static String getTokenValue(HttpServletRequest request){  
    20.     String key = getTokenKey(request);  
    21.     Map<String,String> tokenMap = null;  
    22.     Object obj = request.getSession().getAttribute("tokenMap");  
    23.     if(obj == null){  
    24.         tokenMap = new HashMap<String,String>();  
    25.         request.getSession().setAttribute("tokenMap", tokenMap);  
    26.     } else {  
    27.         tokenMap = (Map<String,String>)obj;  
    28.     }  
    29.     if(tokenMap.containsKey(key)){  
    30.         return tokenMap.get(key);  
    31.     }  
    32.     String value = GUID.generate();//GUID实现可自行百度,其实弄个伪随机数也是可以的...  
    33.     tokenMap.put(key,value);  
    34.     return value;  
    35. }  
    36.   
    37. /** 
    38.  * 验证token 
    39.  */  
    40. public static boolean verify(String key ,String value ,HttpServletRequest request){  
    41.     boolean result = false;  
    42.     if (StringUtil.isEmpty(key) || StringUtil.isEmpty(value)) {//key或value只要有一个不存在就验证不通过  
    43.         return result;  
    44.     }  
    45.   
    46.     if (request.getSession() != null) {  
    47.         Map<String,String> tokenMap = getTokenMap(request);  
    48.         if(value.equals(tokenMap.get(key))){  
    49.             result = true;  
    50.             tokenMap.remove(key);//成功一次就失效  
    51.         }  
    52.     }  
    53.     return result;  
    54. }  


    完成上边的工具方法后,需要在form中添加token,如下:

    [html] view plain copy
     
    1. <form name="frm" action="/test/tokentest.htm"  method="POST">  
    2.     <input type="hidden" name="token_key" value="<%=Token.getTokenKey(request) %>"/>  
    3.     <input type="hidden" name="token_value" value="<%=Token.getTokenValue(request) %>"/>  
    4.     ...  
    5. </form>  


    验证可以放在Filter里也可以放在Service里,只要保证请求/test/tokentest.htm会先验证就行了。直接调用工具方法Token.verify()以下就不赘述了。

    3. 在HTTP头中自定义属性并验证:

    这个方法和上面那个类似,也是设置token,只是把token设置为HTTP头中的自定义属性。

    通过XMLHttpRequest可以一次性给所有该类请求的HTTP头加上token 属性,但是XMLHttpRequest请求通常用于Ajax方法对局部页面的异步刷新,比较有局限性;而且通过XMLHttpRequest请求的地址不会被记录到浏览器的地址栏,一方面不会通过Referer泄露token,另一方面会导致前进,后退,刷新,收藏等操作失效,所以还是慎用。

    虽然上面介绍了几种方法,但现在还没有一种完美的解决方案,但是通过Referer和Token方案结合起来使用,也能很得有效CSRF攻击。

  • 相关阅读:
    学习php 韩顺平 数据类型 三元运算,字符串运算类型运算
    学习php 韩顺平
    贪小便宜吃大亏关于汇泽平板和智能手表
    学习spring的第三天
    学习spring的第二天
    学习spring的第一天
    mybatis批量添加和删除
    关于mybatis的<selectKey>中的keyColumn
    mybatis+maven+父子多模块进行crud以及动态条件查询
    mybatis的插入数据后的主键获取
  • 原文地址:https://www.cnblogs.com/chaoshenzhu/p/7356716.html
Copyright © 2011-2022 走看看