SpringMVC/boot-CSRF安全方案
1. CSRF原理与防御方案概述
一. 原理
增删改的接口参数值都有规律可循,可以被人恶意构造增删改接口
将恶意构造的增删改接口发给对应特定用户,让特定用户点击
特定用户使用自己的认证信息对该接口发起了请求,可能被新增危险信息(比如管理员账号),修改敏感信息(比如退款金额),删除关键信息(比如删除差评)
二. 防御方案概述
参数不可猜解,发起请求时在参数中增加随机token参数
token参数在后台与保存在cookie,session,tair中的token参数进行比对,若不匹配或者没有该参数,则校验不通过
黑客无法获取到特定用户的随机token值,所以杜绝CSRF的危害
2 ali修复方案
一 . 确认应用类型
若为正常业务,提供数据/文件等增删改服务,则需要配置CSRF,请继续看下去
若应用不是Web应用,或者只是HSF服务或者给其他应用服务器调用的API接口服务(纯内网的纯Server to Server,不是通过Login获取登陆态的接口,而是通过AKSK加签名验证签名) ,则不需要配置CSRF,请提供相应加签验签代码给对应答疑或者安全工程师进行确认并关闭漏洞。
二 . 安全包引入
Step1. 配置扩展包POM依赖
注意:SpringMVC扩展安全包引入后会默认开启一系列开关,包括XSS开关,CSRF开关等,从而导致业务短暂出现异常(前端页面乱码,接口访问返回403状态码等),只需要继续按照文档操作下去,业务最终会恢复正常。
1. SpringMVC扩展包
请参考网上SpringMVC安全扩展引入文档
2 SpringBoot扩展包 (starter)
请参考网上SpringBoot安全扩展引入文档
Step2. 查看是否依赖成功
POM配置完成后,在IDEA的External Libraries中查找是否以下包存在
//SpringMVC仅检查这个包
com.alibaba.security:security-spring-webmvc
//SpringBoot仅检查这个包
com.alibaba.security:security-spring-boot-starter
三 . CSRF开关配置
Step1. 显式配置CSRF开关
虽然CSRF在安全包引入之后,会自动开启CSRF拦截,但是为了确保配置可读性以及后续问题排查方便,请在resources下的"application.properties" (若没有,请创建)文件中协商如下配置:
spring.security.csrf.enabled = true
注:开启了该开关之后,所有访问请求都会因为没有token带入被拦截导致访问不成功,需要继续配置下去,让业务恢复正常
Step2. 将token带给前端
配置好开关之后,安全包会生成一个随机字符串,我们称为CSRF_Token,该token会被默认存入cookie中。若使用VM,则可以通过VM调用相关接口获得。
这个Token需要在前端的每个增删改接口请求中作为参数带入给服务器用于校验安全性
不同前端技术方案有不同带入方式:
1 VM后端模板
a. VM后端模板有三种token带入请求的配置方式:
- 在application.properties中统一配置
- CSRF Token 自动生成的URL映射列表,多值使用逗号分隔(默认值为空)
- 当前URL风格为ant风格,风格值由配置项 spring.security.csrf.url.style 决定
spring.security.csrf.token.urls = /csrf_token/**
b. 在Controller类级别使用注解@CsrfTokenModel配置
@Controller
@RequestMapping("/csrf")
@CsrfTokenModel
public class CsrfController {
@RequestMapping("/form")
public String form() {
return "csrf_form";
}
}
c.在Controller类级别使用注解配置
此种情况可以使得该controller下所有模板渲染。都可以通过宏获取token的参数名称和值
在方法级别使用注解@CsrfTokenModel配置
@Controller
@RequestMapping("/csrf")
public class CsrfController {
@RequestMapping("/form")
@CsrfTokenModel
public String form() {
return "csrf_form";
}
}
如果需要CSRF Token校验的Controller或者方法过多时,当前框架还提供一种便利的方式, 即URL映射级别的自动生成方式,只需在application.properties文件中增加如下配置:
CSRF Token 自动生成的URL映射列表,多值使用逗号分隔(默认值为空)
当前URL风格为正则表达式,风格值由配置项 spring.security.csrf.url.style 决定
spring.security.csrf.token.urls = /csrf_token/**
- CSRF Token 模型属性名称
spring.security.csrf.token.model.attribute = csrfToken
后端配置好之后,在VM模板中,针对所有请求form表单,增加对应字段,确保每次请求都能带上
- Velocity Template Code
<form method="post" action="/form/submit">
<input type="hidden" name="${csrfToken.parameterName}" value="${csrfToken.token}">
<input type="text" name="name"/>
<br>
<input type="submit" value="Submit"/>
</form>
- 渲染后的HTML
<form method="post" action="/form/submit">
<input type="hidden" name="_csrf" value="bfe23341-b28c-41a3-bed8-dfbd65385fc8">
<input type="text" name="name"/>
<br>
<input type="submit" value="Submit"/>
</form>
正常情况下如上图所示,渲染后,字段name为p_csrf, value为随机生成的值,同时会在cookie中放入对应字段。请注意,token的字段名一定是要从csrftoken这个obj中取出来的,不能在前端自定义,若要在后端更换字段名,请参考下面的『CSRF定制化功能』
2. ajax前后端分离
ajax发起请求的情况下,token无法直接渲染到页面上,通过下方途径解决该问题。
- 在cookie中读取token,将其带入到ajax请求的参数中。然后传到后端(Cookie中token的key默认为XSRF-TOKEN)
- 若cookie中的XSRF-TOKEN值无法被js读取,请检查该值httponly属性未true,若为true,请在"application.properties"中新增一个配置项,如下:
- 如果是在参数中携带,默认Token名称是_csrf,如果是在header中携带,默认Token名称是X-XSRF-TOKEN
spring.security.csrf.cookieHttpOnly = false
- 设置完成之后,请清除浏览器缓存之后重新尝试获取XSRF-TOKEN值
3. 跨域下的token传输
在一般业务场景下,安全包会将token种到服务端对应的域名cookie下,可以被前端js调用和植入到header或者参数中。但是在跨域场景下,前端页面与后端服务端不是同一个域名,导致无法取到服务端域名下的cookie。
假设aaaa.com要跨域访问bbbb.com的接口,bbbb.com的接口做了csrf校验。此时按照如下步骤进行token交互:
开启CORS跨域头的业务解决方案如下:
1. bbbb.com新增一个接口,返回自身的csrf token
该接口实现示例如下:
@RequestMapping(value = "/ajax", produces = MediaType.APPLICATION_JSON_VALUE)
@CrossOrigin(origins = "http://aaaaaa.com:7001", maxAge = 3600)
@ResponseBody
public CsrfToken getCsrfToken(HttpServletRequest request, HttpServletResponse response) {
CsrfToken csrfToken = csrfTokenRepository.loadToken(request);
if (csrfToken == null) {
csrfToken = csrfTokenRepository.generateToken(request);
csrfTokenRepository.saveToken(csrfToken, request, response);
}
return csrfToken;
}
2. aaaa.com携带with-credentials的头部来获取该token
function callOtherDomain(){
var xhr = new XMLHttpRequest();
if(xhr) {
xhr.open('GET', 'http://bbbbbb.com:7001/csrf/ajax', true);
xhr.withCredentials = true;
xhr.onload = function () {
result.innerHTML = xhr.responseText;
var json = JSON.parse(xhr.responseText);
token_key = json.paramterName;
token = json.token;
};
xhr.send(null);
}
}
3. 将获取到的token存放在客户端上(比如localstorage,或者页面隐藏字段中)
4. aaaa.com 访问bbbb.com其他接口的时候,获取token作为接口参数/头部参数传递给bbbb.com,同时访问该接口时应该设置withcredentials = true:
function buttonClick(token_key, token){
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://bbbbbb.com:7001/csrf/cors/check');
xhr.withCredentials = true;
xhr.onload = function () {
result.innerHTML = xhr.responseText;
};
xhr.onerror = function () {
result.innerHTML = "Error!";
}
xhr.send(token_key + '=' + token + '&' + otherparams)
}
Step3. 后端进行Token校验
后端进行token校验,目前只提供全局url检查方式,在没有显式配置情况下默认对所有POST请求进行token检查,为了更好的对业务进行支持,建议在classpath下的application.properties进行显式配置,如下:
//根据业务需求进行配置是否拦截GET请求,安全要求POST请求必须拦截
spring.security.csrf.supportedMethods = POST,GET
//使用ant风格配置需要进行token检查的url(安全要求对所有增删改进行token校验)
spring.security.csrf.url.included = /**
//使用ant风格配置无需需要进行token检查的url,只能对查询接口进行excluded
spring.security.csrf.url.excluded = /csrf/nocheck
校验之后,若成功,则会顺利执行对应后台功能,若失败,则会返回403的状态码或者301跳转taobao.error的情况,如下:
status : 403
message : Invalid CSRF Token '' was found on the request parameter 'p_csrf' or header 'h_csrf'.
===
status: 301
location: err2.taobao.com
SpringMVC/boot-CSRF安全方案的更多相关文章
- spring boot 自动部署方案
现在主流的自动部署方案大都是基于Docker的了,但传统的自动部署方案比较适合中小型公司,下面的方案就是比较传统的自动部署方案. 1.为什么需要自动部署 基于微服务的架构,自动部署显得非常重要.因为每 ...
- Java springmvc 统一异常处理的方案
前言:为什么要统一异常处理?经常在项目中需要统一处理异常,将异常封装转给前端.也有时需要在项目中统一处理异常后,记录异常日志,做一下统一处理. Springmvc 异常统一处理的方式有三种. 一.使用 ...
- Jenkins spring boot 自动部署方案
原文地址:http://www.cnblogs.com/skyblog/p/5632869.html 现在主流的自动部署方案大都是基于Docker的了,但传统的自动部署方案比较适合中小型公司,下面的方 ...
- spring boot动态数据源方案
动态数据源 1.背景 动态数据源在实际的业务场景下需求很多,而且想要沟通多数据库确实需要封装这种工具,针对于bi工具可能涉及到从不同的业务库或者数据仓库中获取数据,动态数据源就更加有意义. 2.依赖 ...
- Spring Boot统一异常处理方案示例
一.异常处理的原则 1.调用方法的时候返回布尔值来代替返回null,这样可以 NullPointerException.由于空指针是java异常里最恶心的异常. 2. catch块里别不写代码.空ca ...
- [加密]ESP32 -Secure Boot 安全方案
转自:https://blog.csdn.net/espressif/article/details/79362094 Secure Boot 功能概述 方案概述 Secure Boot 的目的是保证 ...
- SpringMVC -- 梗概--壹
1.springMVC:MVC开源框架 2.springMVC开发流程: 2.1 导包: 2.2 配置前端控制器(核心) DispatcherServlet <servlet> <s ...
- AVR单片机的BOOT区
BOOT区的由来基于一个简单的道理,即单片机的程序是保存在FLASH中的,要运行程序就必须不停的访问FLASH存储器.对于一般的FLASH存储器,数据的写入需要一定的时间来完成,在数据写入完成之前,存 ...
- 使用Spring Boot Actuator、Jolokia和Grafana实现准实时监控
由于最近在做监控方面的工作,因此也读了不少相关的经验分享.其中有这样一篇文章总结了一些基于Spring Boot的监控方案,因此翻译了一下,希望可以对大家有所帮助. 原文:Near real-time ...
- 单片机成长之路(avr基础篇)- 003 AVR单片机的BOOT区
BOOT区的由来基于一个简单的道理,即单片机的程序是保存在FLASH中的,要运行程序就必须不停的访问FLASH存储器.对于一般的FLASH存储器,数据的写入需要一定的时间来完成,在数据写入完成之前,存 ...
随机推荐
- buu 相册
一.拖入jeb,这个神器里面,感觉对jeb使用还是不熟悉,对我逆向产生了一些障碍. 抓住题目给的提示,邮箱,全局直接搜索,mail. 看下它的交叉引用 找到了发邮件的方法, C2的MAILFROME说 ...
- echarts堆叠柱状图在最上面的柱子显示总和
需求 柱子需设置barMinHeight 在堆叠柱状图的最上面显示当前堆叠的总和 直接上代码吧 需要注意:设置barMinHeight时为了让0不显示,只能将0设置为null; 设置为null的柱子l ...
- 【BZOJ 4771】七彩树
一直TLE的原因竟然是数组开太大了导致\(memset\)清空耗时超限,亏我还调了1天啊(T^T) 题目大意 给定一颗树,每个节点都有一个颜色,要求多次询问某个节点\(x\)的子树中深度不超过\(d\ ...
- Spring MVC中的M V C
M→Model 模型 V→View 视图 C→Controller 控制器 也就是说一次交互由生到死(请求到相应) 需要经过 这三个层级 来完成 那么为什么这么设计 这么设计又有什么好处 我是这么认为 ...
- 添加Lombok插件后调用Setter或Getter方法IDEA编译错误
虽然添加Lombok插件,但是调用Setter或Getter方法IDEA编译错误,主要原因如下 解决办法:
- 转载:使用jquery刷新当前页面以及其他js知识积累
转载:https://www.cnblogs.com/heguihui/p/10505949.html 如何使用jquery刷新当前页面 下面介绍全页面刷新方法:有时候可能会用到 window.loc ...
- Socket介绍(五)
套接字(socket)是一个抽象层,应用程序可以通过它发送或接收数据,可对其进行像对文件一样的打开.读写和关闭等操作.套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信.网络套接 ...
- C++第四十九篇 -- 将一个项目Copy到另一台电脑
最近写项目,由于设备原因,需要将一台电脑的项目拷贝到另一台电脑上,在另一个电脑上继续编写.由于配置属性原因,最终还是在另一台电脑上创建了新项目,只是把这些cpp文件都复制过去了,然后重新部署属性. 背 ...
- python虚拟环境之Pyenv
一.windows下安装 1.使用命令安装 pip install pyenv-win --target %USERPROFILE%/.pyenv %USERPROFILE%/是具体的路径,例如 ## ...
- Linux[Manjaro] 小新15笔记本AMD ryzen锐龙4800U,在安装系统后出现的随即死机冻屏问题
Linux[Manjaro] 小新15AMD ryzen锐龙4800U,在安装系统后出现的随即死机冻屏问题解决办法 年初尝试将manjaro安装在我的笔记本上就存在这个问题,也一度将我劝退.系统安装在 ...