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存储器,数据的写入需要一定的时间来完成,在数据写入完成之前,存 ...
随机推荐
- PHP安装amqp扩展 出现未装librabbitmq错误
这错误的原因是因为没有安装amqp的依赖包rabbitmq-c,需要先安装rabbitmq-c. 1.安装rabbitmq-c-0.7.1 没有安装就会提示上面的错误我选择的是最新版本0.7.1 wg ...
- Linux学习之路(RPM和YUM)
rpm包的管理 介绍: 一种用于互联网下载包的打包及安装工具(类似windows中的setup).它包含在某些Linux分发版中.它生成具有RPM扩展名的文件.RPM是RedHat软件包管理工具缩写, ...
- OSI与TCP/IP各层的结构与功能,都有哪些协议?
学习计算机⽹络时我们⼀般采⽤折中的办法,也就是中和 OSI 和 TCP/IP 的优点,采⽤⼀种只有 五层协议的体系结构,这样既简洁⼜能将概念阐述清楚. 结合互联⽹的情况,⾃上⽽下地,⾮常简要的介绍⼀下 ...
- MySQL 那些常见的错误设计规范
依托于互联网的发达,我们可以随时随地利用一些等车或坐地铁的碎片时间学习以及了解资讯.同时发达的互联网也方便人们能够快速分享自己的知识,与相同爱好和需求的朋友们一起共同讨论. 但是过于方便的分享也让知识 ...
- 自定义注解@MyBatisRepository
新建一个注解用作dao扫描 /** * @author fuguangli * @description 标识MyBatis的DAO,方便{@link org.mybatis.spring.mappe ...
- 如何快速更新长缓存的 HTTP 资源
前言 HTTP 缓存时间一直让开发者头疼.时间太短,性能不够好:时间太长,更新不及时.当遇到严重问题需紧急修复时,尽管后端文件可快速替换,但前端文件仍从本地缓存加载,导致更新长时间无法生效. 对于这个 ...
- Spring Boot邮箱链接注册验证
Spring Boot邮箱链接注册验证 简单介绍 注册流程 [1]前端提交注册信息 [2]后端接受数据 [3]后端生成一个UUID做为token,将token作为redis的key值,用户数据作为re ...
- java反序列化提取payload之xray 高级版的shiro回显poc的提取过程
本文中xray高级版shiro payload来源于雷石安全实验室公众号发布的shiroExploit.jar 感谢雷石安全实验室,雷石安全实验室牛逼 本文主要描述如何从shiro的payload中提 ...
- PAT乙级:1069 微博转发抽奖 (20分)
PAT乙级:1069 微博转发抽奖 (20分) 题干 小明 PAT 考了满分,高兴之余决定发起微博转发抽奖活动,从转发的网友中按顺序每隔 N 个人就发出一个红包.请你编写程序帮助他确定中奖名单. 输入 ...
- ubuntu16.04细节设置
1.查看无线网卡名称 $ iwconfig ------------------ lo no wireless extensions. eth1 no wireless extensions. eth ...