Java解决CSRF问题

时间:2022-11-10 11:24:27

项目地址: https://github.com/morethink/web-security

CSRF是什么?

CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSRF/XSRF。

CSRF可以做什么?

你这可以这么理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账......造成的问题包括:个人隐私泄露以及财产安全。

CSRF的原理

下图简单阐述了CSRF攻击的思

Java解决CSRF问题

从上图可以看出,要完成一次CSRF攻击,受害者必须依次完成两个步骤:

  1. 登录受信任网站A,并在本地生成Cookie。
  2. 在不登出A的情况下,访问危险网站B。

看到这里,你也许会说:“如果我不满足以上两个条件中的一个,我就不会受到CSRF的攻击”。是的,确实如此,但你不能保证以下情况不会发生:

  1. 你不能保证你登录了一个网站后,不再打开一个tab页面并访问另外的网站。
  2. 你不能保证你关闭浏览器了后,你本地的Cookie立刻过期,你上次的会话已经结束。(事实上,关闭浏览器不能结束一个会话,但大多数人都会错误的认为关闭浏览器就等于退出登录/结束会话了......)
  3. 上图中所谓的攻击网站,可能是一个存在其他漏洞的可信任的经常被人访问的网站。

下面讲一讲java解决CSRF攻击的方式。

模拟CSRF攻击

登录A网站

用户名和密码都是admin。

http://localhost:8081/login.html:

Java解决CSRF问题

你有权限删除1号帖子

http://localhost:8081/deletePost.html:

Java解决CSRF问题

登录有CSRF攻击A网站的B网站

http://localhost:8082/deletePost.html:

Java解决CSRF问题

明显看到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

Java解决CSRF问题

B网站的他已经没有权限了

我们通过UserFilter.java给攻击者返回的是403错误,表示服务器理解用户客户端的请求但拒绝处理。

http://localhost:8082/deletePost.html:

Java解决CSRF问题

攻击者不能删除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 { }
}

注意

  1. cookie必须要设置PATH才可以生效,否则在下一次请求的时候无法带给服务器。
  2. Spring Boot 出现启动找不到主类的问题时可以mvn clean一下。
  3. Filter设置response.sendError(403)在Spring Boot没有效果。

参考文档

  1. 浅谈CSRF攻击方式
  2. jQueue 动态设置form表单的action属性的值和方法
  3. javascript的String到int(32位)的hash算法

Java解决CSRF问题的更多相关文章

  1. java 解决Hash&lpar;散列&rpar;冲突的四种方法--开放定址法&lpar;线性探测&comma;二次探测&comma;伪随机探测&rpar;、链地址法、再哈希、建立公共溢出区

    java 解决Hash(散列)冲突的四种方法--开放定址法(线性探测,二次探测,伪随机探测).链地址法.再哈希.建立公共溢出区 标签: hashmaphashmap冲突解决冲突的方法冲突 2016-0 ...

  2. JAVA &vert; Java 解决跨域问题

    JAVA | Java 解决跨域问题 Table of Contents 引言 什么是跨域(CORS) 什么情况会跨域 解决方案 前端解决方案 后端解决方案 具体方式 一.使用Filter方式进行设置 ...

  3. Java解决大文件读取的内存问题以及文件流的比较

    Java解决大文件读取的内存问题以及文件流的比较 传统方式 读取文件的方式一般是是从内存中读取,官方提供了几种方式,如BufferedReader, 以及InputStream 系列的,也有封装好的如 ...

  4. java 解决中文乱码

    //1.代码解决 public class LuanMa { public static String getNewString(String luanma){ String result = &qu ...

  5. 约瑟夫环的java解决

    总共3中解决方法,1.数学推导,2.使用ArrayList递归解决,3.使用首位相连的LinkedList解决 import java.util.ArrayList; /** * 约瑟夫环问题 * 需 ...

  6. java 解决JFrame不能设置背景色的问题 分类: Java Game 2014-08-15 09&colon;48 119人阅读 评论&lpar;0&rpar; 收藏

    这段时间比较多,于是写一写JAVA的一些IT技术文章.如有JAVA高手请加QQ:314783246,互相讨论. 在Java的GUI设计中,Frame和JFrame两者之间有很大差别,上次刚学时编一个窗 ...

  7. Java解决TopK问题(使用集合和直接实现)

    在处理大量数据的时候,有时候往往需要找出Top前几的数据,这时候如果直接对数据进行排序,在处理海量数据的时候往往就是不可行的了,而且在排序最好的时间复杂度为nlogn,当n远大于需要获取到的数据的时候 ...

  8. 关于eclipse新建web项目&comma;提示&colon;&quot&semi;The superclass &quot&semi;javax&period;servlet&period;http&period;HttpServlet&quot&semi; was not found on the Java&quot&semi;解决办法

    新建jsp页面老提示: Multiple annotations found at this line: - The superclass "javax.servlet.http.HttpS ...

  9. 解决No &&num;39&semi;Access-Control-Allow-Origin&&num;39&semi; header is present on the requested resource&period;跨域问题(后台&lpar;java&rpar;解决方法)

    附:前端常见跨域解决方案(全) 跨域错误 解决方法 在后台写一个过滤器来改写请求头 附上一个前端不知所以然的后台java代码: public class CorsFilter implements F ...

随机推荐

  1. Python学习笔记(五)&mdash&semi;&mdash&semi;list和tuple

    一.list 1.定义: list是一种有序的集合,可以随时添加和删除其中的元素 2.声明方法: subjects=['Math','English', 'Chinese'] 3.一些api (1)获 ...

  2. Oracle中较长number型数值的科学计数显示问题

    表中有id列,类型为number(38).在sqlplus中查询的时候,查询结果的显示方式为科学计数法: ID ---------- 4.5572E+18 4.5574E+18 4.5585E+18 ...

  3. 使用Ant自动化我们的java项目生成

    现在我们已经了解如何定义属性.依赖关系以及如何运行ant,接下来我们将学习怎样使用ant编译java源代码并生成jar文件. 编译源代码 由于Ant的主要目标就是生成java应用程序,它内置了java ...

  4. centos升级mysql至5&period;7

    1.备份原数据库 [root@www ~] #mysqldump -u root –p -E –all-database > /home/db-backup.sql 加-E是因为mysqldum ...

  5. 「Ruby &amp&semi;&amp&semi; Sqlite3」How to install sqlite3 for ruby&quest; &lpar;solve&colon; sqlite-ruby no such file&period;&period;&period;&rpar;

    error message:           no such file .... 安装 gem install sqlite3-ruby -- --with-sqlite3-dir=/usr/lo ...

  6. boost环境搭建

    切换到boost目录下面,使用编译命令>bjam.exe --with-date_time --toolset=msvc-9.0 --build-type=complete stage --wi ...

  7. MINA、Netty、Twisted一起学(十二):HTTPS

    由于HTTPS协议是由HTTP协议加上SSL/TLS协议组合而成,在阅读本文前可以先阅读一下HTTP服务器和SSL/TLS两篇博文,本文中的代码也是由这两篇博文中的代码组合而成. HTTPS介绍 上一 ...

  8. EF 批量 添加 修改 删除

    1批量添加    db.T_Investigator.AddRange(list) 2批量删除    db.T_Investigator.RemoveRange(list) 3批量修改   for 循 ...

  9. PHP CLI模式下的多进程应用

    作者: Laruence(   ) 本文地址: http://www.laruence.com/2009/06/11/930.html 转载请注明出处 PHP在很多时候不适合做常驻的SHELL进程, ...

  10. 图形界面至少要有一个*Swing容器

    图形界面至少要有一个*Swing容器 *Swing容器为其它Swing组件在屏幕上的绘制和处理事件提供支持 常用的*容器: JFrame(框架):表示主程序窗口 JDialog(对话框):每个J ...