Java解决CSRF问题
项目地址: https://github.com/morethink/web-security
CSRF是什么?
CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSRF/XSRF。
CSRF可以做什么?
你这可以这么理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账......造成的问题包括:个人隐私泄露以及财产安全。
CSRF的原理
下图简单阐述了CSRF攻击的思
从上图可以看出,要完成一次CSRF攻击,受害者必须依次完成两个步骤:
- 登录受信任网站A,并在本地生成Cookie。
- 在不登出A的情况下,访问危险网站B。
看到这里,你也许会说:“如果我不满足以上两个条件中的一个,我就不会受到CSRF的攻击”。是的,确实如此,但你不能保证以下情况不会发生:
- 你不能保证你登录了一个网站后,不再打开一个tab页面并访问另外的网站。
- 你不能保证你关闭浏览器了后,你本地的Cookie立刻过期,你上次的会话已经结束。(事实上,关闭浏览器不能结束一个会话,但大多数人都会错误的认为关闭浏览器就等于退出登录/结束会话了......)
- 上图中所谓的攻击网站,可能是一个存在其他漏洞的可信任的经常被人访问的网站。
下面讲一讲java解决CSRF攻击的方式。
模拟CSRF攻击
登录A网站
用户名和密码都是admin。
http://localhost:8081/login.html
:
你有权限删除1号帖子
http://localhost:8081/deletePost.html
:
登录有CSRF攻击A网站的B网站
http://localhost:8082/deletePost.html
:
明显看到B网站是8082端口,A网站是8081端口,但是B网站的删除2号帖子功能依然实现。
预防CSRF攻击
简单来说,CSRF 就是网站 A 对用户建立信任关系后,在网站 B 上利用这种信任关系,跨站点向网站 A 发起一些伪造的用户操作请求,以达到攻击的目的。
而之所以可以完成攻击是因为B向A发起攻击的时候会把A网站的cookie带给A网站,也就是说cookie已经不安全了。
通过Synchronizer Tokens
Synchronizer Tokens: 在表单里隐藏一个随机变化的 csrf_token csrf_token 提交到后台进行验证,如果验证通过则可以继续执行操作。这种情况有效的主要原因是网站 B 拿不到网站 A 表单里的 csrf_token
这种方式的使用条件是PHP和JSP等。因为cookie已经不安全了,因此把csrf_token值存储在session中,然后每次表单提交时都从session取出来放到form表单的隐藏域中,这样B网站不可以得到这个存储到session中的值。
下面是JSP的:
<input type="hidden" name="random_form" value=<%=random%>></input>
但是我现在的情况是html,不是JSP,并不能动态的从session中取出csrf_token值。只能采用加密的方式了。
Hash加密cookie中csrf_token值
这可能是最简单的解决方案了,因为攻击者不能获得第三方的Cookie(理论上),所以表单中的数据也就构造失败了。
我采用的hash加密方法是JS实现Java的HashCode方法,得到hash值,这个比较简单。也可以采用其他的hash算法。
前端向后台传递hash之后的csrf_token值和cookie中的csrf_token值,后台拿到cookie中的csrf_token值后得到hashCode值然后与前端传过来的值进行比较,一样则通过。
你有权限删除3号帖子
http://localhost:8081/deletePost.html
B网站的他已经没有权限了
我们通过UserFilter.java给攻击者返回的是403错误,表示服务器理解用户客户端的请求但拒绝处理。
http://localhost:8082/deletePost.html
:
攻击者不能删除4号帖子。
前端代码:
deletePost.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>deletePost</title>
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript">
function deletePost() {
var url = '/post/' + document.getElementById("postId").value;
var csrf_token = document.cookie.replace(/(?:(?:^|.*;\s*)csrf_token\s*\=\s*([^;]*).*$)|^.*$/, "$1");
console.log('csrf_token=' + csrf_token);
$.ajax({
type: "post",//请求方式
url: url, //发送请求地址
timeout: 30000,//超时时间:30秒
data: {
"_method": "delete",
"csrf_token": hash(csrf_token) // 对csrf_token进行hash加密
},
dataType: "json",//设置返回数据的格式
success: function (result) {
if (result.message == "success") {
// window.location.href = "index.html";
$("#result").text("删除成功");
} else {
$("#result").text("删除失败");
}
},
error: function () { //请求出错的处理
$("#result").text("请求出错");
}
});
}
// javascript的String到int(32位)的hash算法
function hash(str) {
var hash = 0;
if (str.length == 0) return hash;
for (i = 0; i < str.length; i++) {
char = str.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash; // Convert to 32bit integer
}
return hash;
}
</script>
</head>
<body>
<h3>删除帖子</h3>
帖子编号 : <input type="text" id="postId"/>
<button onclick="deletePost();">deletePost</button>
<br/>
<br/>
<br/>
<div>
<p id="result"></p>
</div>
</body>
</html>
后台代码:
UserInterceptor.java
package cn.morethink.interceptor;
import cn.morethink.util.JsonUtil;
import cn.morethink.util.Result;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
/**
* @author 李文浩
* @date 2018/1/4
*/
public class UserInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String method = request.getMethod();
System.out.println(method);
if (method.equalsIgnoreCase("POST") || method.equalsIgnoreCase("DELETE")
|| method.equalsIgnoreCase("PUT")) {
String csrf_token = request.getParameter("csrf_token");
System.out.println(csrf_token + "1222222222222222222222222222222222222222222222");
Cookie[] cookies = request.getCookies();
if (cookies != null && cookies.length > 0 && csrf_token != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals("csrf_token")) {
if (Integer.valueOf(csrf_token) == cookie.getValue().hashCode()) {
return true;
}
}
}
}
}
Result result = new Result("403", "你还想攻击我??????????", "");
PrintWriter out = response.getWriter();
out.write(JsonUtil.toJson(result));
out.close();
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
注意:
- cookie必须要设置PATH才可以生效,否则在下一次请求的时候无法带给服务器。
- Spring Boot 出现启动找不到主类的问题时可以mvn clean一下。
- Filter设置response.sendError(403)在Spring Boot没有效果。
参考文档:
Java解决CSRF问题的更多相关文章
- java 解决Hash(散列)冲突的四种方法--开放定址法(线性探测,二次探测,伪随机探测)、链地址法、再哈希、建立公共溢出区
java 解决Hash(散列)冲突的四种方法--开放定址法(线性探测,二次探测,伪随机探测).链地址法.再哈希.建立公共溢出区 标签: hashmaphashmap冲突解决冲突的方法冲突 2016-0 ...
- JAVA | Java 解决跨域问题
JAVA | Java 解决跨域问题 Table of Contents 引言 什么是跨域(CORS) 什么情况会跨域 解决方案 前端解决方案 后端解决方案 具体方式 一.使用Filter方式进行设置 ...
- Java解决大文件读取的内存问题以及文件流的比较
Java解决大文件读取的内存问题以及文件流的比较 传统方式 读取文件的方式一般是是从内存中读取,官方提供了几种方式,如BufferedReader, 以及InputStream 系列的,也有封装好的如 ...
- java 解决中文乱码
//1.代码解决 public class LuanMa { public static String getNewString(String luanma){ String result = &qu ...
- 约瑟夫环的java解决
总共3中解决方法,1.数学推导,2.使用ArrayList递归解决,3.使用首位相连的LinkedList解决 import java.util.ArrayList; /** * 约瑟夫环问题 * 需 ...
- java 解决JFrame不能设置背景色的问题 分类: Java Game 2014-08-15 09:48 119人阅读 评论(0) 收藏
这段时间比较多,于是写一写JAVA的一些IT技术文章.如有JAVA高手请加QQ:314783246,互相讨论. 在Java的GUI设计中,Frame和JFrame两者之间有很大差别,上次刚学时编一个窗 ...
- Java解决TopK问题(使用集合和直接实现)
在处理大量数据的时候,有时候往往需要找出Top前几的数据,这时候如果直接对数据进行排序,在处理海量数据的时候往往就是不可行的了,而且在排序最好的时间复杂度为nlogn,当n远大于需要获取到的数据的时候 ...
- 关于eclipse新建web项目,提示:"The superclass "javax.servlet.http.HttpServlet" was not found on the Java"解决办法
新建jsp页面老提示: Multiple annotations found at this line: - The superclass "javax.servlet.http.HttpS ...
- 解决No 'Access-Control-Allow-Origin' header is present on the requested resource.跨域问题(后台(java)解决方法)
附:前端常见跨域解决方案(全) 跨域错误 解决方法 在后台写一个过滤器来改写请求头 附上一个前端不知所以然的后台java代码: public class CorsFilter implements F ...
随机推荐
- window下mySql数据库设置密码
方法一:用setpassword命令 首先登陆MySQL:mysql -u root 格式:mysql> set password for 用户名@localhost = password('新 ...
- 原来你是这样的JAVA[03]-继承、多态、抽象类
一.继承 Java中的继承使用关键字extends ,跟C#的语法略有差别. 1.子类构造器 java会自动在子类的构造器中插入对父类构造器的调用,也就是说在子类可以访问父类之前已经完成了父类的初始化 ...
- python网站目录扫描器2.0版
改进了上次乱的要死的. #网站目录扫描器2.0的脚本 import sys import requests import time print('[+]扫描中') def gfc(): f=open( ...
- 2017ICPC/广西邀请赛1001(水)HDU6181
A Math Problem Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)To ...
- UVA 572 dfs求连通块
The GeoSurvComp geologic survey company is responsible for detecting underground oil deposits. GeoSu ...
- 2017ecjtu-summer training #3 POJ3264
...
- Stars(树状数组)
http://acm.hdu.edu.cn/showproblem.php?pid=1541 Stars Time Limit: 2000/1000 MS (Java/Others) Memor ...
- Java应用开发中的字符集与字符编码
事出有因 在向HttpURLConnection的输出流写入内容时,因没有设置charset,导致接收方对数据的验签不一致. URL url = new URL(requestUrl); //打开连接 ...
- ASP.NET没有魔法——ASP.NET OAuth、jwt、OpenID Connect
上一篇文章介绍了OAuth2.0以及如何使用.Net来实现基于OAuth的身份验证,本文是对上一篇文章的补充,主要是介绍OAuth与Jwt以及OpenID Connect之间的关系与区别. 本文主要内 ...
- Kafka集群的搭建
Kafka集群的搭建 node1 node2 node3 kafka须用版本(kafka-0.8.2.2),否则不兼容spark1.6 1.启动zookeeper集群node1 node2 ...