一文从容应对CSRF

简介: 在开发中相信相信很多人都会注意到CSRF这个东西,那这个是什么呢,隐隐约约只知道这是个安全策略。但是具体做什么,有什么用,防哪些安全隐患的却知道的不甚清楚。笔者带着疑问查了一些资料,在这里做个总结。

前言:

在开发中相信相信很多人都会注意到CSRF这个东西,那这个是什么呢,隐隐约约只知道这是个安全策略。但是具体做什么,有什么用,防哪些安全隐患的却知道的不甚清楚。笔者带着疑问查了一些资料,在这里做个总结。


一、CSRF



1.CSRF是什么?


跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。以上的解释就是官方给的CSRF的解释,解释比较简短,若是需要深刻理解CSRF的攻击方式还需要通过例子来说明CSRF的攻击过程。下面就来详细说下CSRF的攻击过程。


2.CSRF如何实现攻击?

20210527144811966.png

上面这张图就是一个典型的CSRF攻击的流程:


第一步:Tom登录银行网站没有退出,此时Tom使用的浏览器中包含了Tom在银行的身份验证信息。


第二步:黑客或者称为攻击人员在一个帖子中加入了超链接,这个超链接就是Tom已经登录的银行的转账地址。


第三步:Tom在没有正常退出银行网站时,就去点击了第二步攻击人员设置的帖子。

第四步:银行收到攻击人员设置的转账请求,然后发现当前请求是Tom发起的(因为浏览器Cookie中仍存在Tom的登录信息),银行发起转账此时Tom的账户资金就被窃取了。


我们可以发现以上攻击可以实施的前提是第一步和第二步都满足了,只有满足了这两步Tom去浏览攻击者的帖子才会有账户被盗的风险,有人觉得这只是一个低概率事件,并不一定会触发这种场景,但是在安全的范围内这是一个漏洞,是企业中严令禁止的。我们不能将风险放任到客户自己的操作上,这样一旦客户操作失误,就会出现重大的生产事故,所以这种CSRF的攻击方式是需要每个项目去考虑的,那这种风险应该怎么去解决呢?下面就来说下如何预防CSRF这种攻击方式。


二、预防CSRF攻击的方式



要说预防CSRF的攻击,必须要说Referer,那Referer是什么呢?


1.Referer是什么?


Referer是Http请求头header的一部分,当浏览器向web服务器发送请求的时候,一般会带上Referer,告诉服务器该网页是从哪个页面链接过来的,服务器因此可以获得一些信息用于处理。Referer的正确英语拼法是referrer。由于早期HTTP规范的拼写错误,为了保持向后兼容就将错就错了。其它网络技术的规范企图修正此问题,使用正确拼法,所以拼法出现了不统一的情况。


上面是官方给出的Referer的定义,现在已经清楚了,当使用浏览器访问web服务器时,请求头中就会有Referer这个字段,这个字段用来表示请求的来源,下面是一个例子:


2021052715180110.png


可以看到笔者打开的W3Cschool网站中点开的一个链接,当前的请求头中就出现了referer这个字段。这里必须要说明的是该字段可以实现不发送,因为笔者是后端开发,对于实现的机制也不是太了解。但是是可以实现的,所以很多请求点开是不会有Referer这个字段的。那我们要怎么使用Referer来预防CSRF攻击呢?


2.使用Referer来预防CSRF攻击


上面给的Tom账户被盗的例子,这里接着用这个例子来说明,当Tom登录了银行系统去发起转账时,那么此时转账请求中的Referer的值应该是银行网站的域名,但是当Tom点击了攻击者的帖子而发起转账时Referer的值应该是帖子所在的域名。这两者是不同的。所以如果银行系统在每次发起转账时对请求头中的Referer进行验证,只对于Referer是本站内的域名时才放行操作,就可以杜绝这种攻击。这种预防CSRF攻击的解决方案是最简单的一种,也是应用最多的一种,笔者目前正在做的项目就是使用的这种方法。

那Referer是绝对安全的吗?


当然也不是,没有一种技术是无懈可击的,这种使用Referer来判断请求来源的方式也不是百分百安全的。因为有工具可以篡改Referer的值,让你以为是真的客户发送的请求,此外Referer是http的规范,有的浏览器并没有实现,当然了主流的浏览器基本全都实现了,但是不能保证所有人使用的浏览器都是主流浏览器,所以这种解决方式并不是百分百安全的。


3.另一种预防CSRF攻击的策略


CSRF的攻击策略很明显就是借助用户浏览器的cookie信息来完成伪登录的,那么只要我们使用的验证信息不在cookie中,CSRF就不能完成攻击,现在常用的就是前端每次访问接口都是需要验证token,前后端的交互依赖token来进行,至于前端token存储在哪,反正不能存在cookie中,可以存sessionstorage等地方,这样一旦token验证失败,就认为是不正常的操作。


三、生产预防CSRF实践



笔者目前所在的项目是一个电商项目,对于预防CSRF的攻击使用了Referer验证与Token验证的方式来预防。双重保证下基本不会有CSRF攻击的出现,具体的措施是使用了两个拦截器,一个token登录拦截器,该拦截器拦截用户传递的token然后去统一用户进行验证,一个是CSRF拦截器验证请求头中的Referer是否是已信任的域名。

下面展示下CSRF拦截器关键代码。


1.CSRF拦截器


这种拦截很简单,就是获取请求头中的Referer然后和已配置的白名单进行比对,发现是白名单一员,则允许通过,若不是则拒绝。

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
        String referer = request.getHeader("Referer");
        String flag = getFlagValue();//拦截器开关
        String whiteUrls = getWhiteUrlValues();//获取Referer白名单,只有白名单成员的请求才可以进入到系统
        //判断是否启用refer过滤 1:开启; 0:关闭
        if ("1".equals(flag)) {
            if (StringUtil.isNotNull(referer)) {
                if (StringUtil.checkUrlCSRF(referer, whiteUrls)) {
                    return true;
                } else {
                    returnCSRF(response);
                    return false;
                }
            } else {
                returnCSRF(response);
                return false;
            }
        }
        return true;
    }
    public static boolean checkUrlCSRF(String refer, String whileUrls)
  {
    if(isNotNull(refer)){
      List<String> whiteUrlList = new ArrayList<String>();
      whiteUrlList = Arrays.asList(whileUrls.split(";"));
      if(whiteUrlList != null && whiteUrlList.size() > 0){
        for(int i = 0; i < whiteUrlList.size(); i++){
          if(refer.indexOf(whiteUrlList.get(i)) == 0){
            return true;
          }
        }
        return false;
      }
    }
    return true;
  }
  private void returnCSRF(HttpServletResponse response) throws Exception {
          ResultDTO resultDTO = new ResultDTO(ExceptionEnum.AUTHORITY_CSRF_30.getResultCode(), null, ExceptionEnum.AUTHORITY_CSRF_30.getResultMsg());
          response.setStatus(403);
          response.setHeader("Access-Control-Allow-Origin", "-");
          response.setHeader("Access-Control-Allow-Credentials", "false");
          JSONObject jsonObject = new JSONObject();
          jsonObject.put("resultDTO", resultDTO);
          JsonSerializerUtil.returnJson(response, jsonObject.toString());
          resultDTO = null;
      }


四、总结



这篇文章总结了CSRF攻击的原理,以及怎么去预防CSRF的攻击。然后说明了现在互联网公司是如何来解决CSRF攻击的场景,希望看到此篇文章的人从此对CSRF都不在迷惑,也可以从容应对这种攻击手段。CSRF攻击是一种偏向于安全的东西,但是作为后端开发确实是必须掌握的,假如需要你设计一个系统架构,架构是设计出来了,但是安全漏洞有很多等于没用,如果攻击者可以轻松的攻击你的系统,那这个系统还有什么存在的意义呢。



相关文章
|
JavaScript Java 测试技术
基于springboot+vue.js的企业级工位管理系统附带文章和源代码设计说明文档ppt
基于springboot+vue.js的企业级工位管理系统附带文章和源代码设计说明文档ppt
199 6
|
编解码 算法
掌握PWM:STM32F103实现PWM控制直流电机小风扇
PWM,即脉冲宽度调制(Pulse Width Modulation),是一种广泛应用于电子和电机控制领域的信号编码方法。PWM的核心思想是通过改变数字信号的脉冲宽度来模拟模拟信号的幅度变化,从而达到控制输出功率的目的。
2329 0
|
安全 Shell Linux
Webshell管理工具:AntSword(中国蚁剑)
中国蚁剑的下载、安装、详细使用步骤
6188 1
|
Java API 容器
常见面试题(jdk1.8的新特性(高薪常问))
jdk1.8的新特性(高薪常问)
696 0
|
SQL 数据库 Python
sqlmap的安装及使用教程_sqlmap安装使用教程
sqlmap的安装及使用教程_sqlmap安装使用教程
|
安全 网络安全
网络安全单兵工具 -- YAKIT
网络安全单兵工具 -- YAKIT
2997 0
java.lang.Exception: Apparent connection leak detected
java.lang.Exception: Apparent connection leak detected
502 0
|
移动开发 JavaScript 前端开发
vue-router 中常用的 hash 和 history 路由模式实现原理
vue-router 中常用的 hash 和 history 路由模式实现原理
250 0
|
C++
C++常用字符串分割方法
来源:http://www.jb51.net/article/55954.htm 一、用strtok函数进行字符串分割 原型: char *strtok(char *str, const char *delim); 功能:分解字符串为一组字符串。 参数说明:str为要分解的字符串,delim为分隔符字符串。 返回值:从str开头开始的一个个被分
6990 0