Java -- CSRF 攻击原理及防御

news/2024/5/18 14:12:22 标签: java, cookie, python, 安全, ajax

什么是CSRF攻击

CSRF(Cross-site request forgery)跨站请求伪造:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。利用受害者在被攻击网站已经获取的注册凭证(比如cookie),绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的。

一个典型的CSRF攻击有着如下的流程:

1、 用户C打开浏览器,访问受信任网站A,输入用户名和密码请求登录网站A;

2、在用户信息通过验证后,网站A产生Cookie信息并返回给浏览器,此时用户登录网站A成功,可以正常发送请求到网站A;

3、用户未退出网站A之前,在同一浏览器中,打开一个TAB页访问网站B(内含恶意代码);

4、网站B接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点A;

5、浏览器在接收到这些攻击性代码后,根据网站B的请求,在用户不知情的情况下携带Cookie信息,向网站A发出请求。网站A并不知道该请求其实是由B发起的,所以会根据用户C的Cookie信息以C的权限处理该请求,导致来自网站B的恶意代码被执行。

在这里插入图片描述

注意:CSRF攻击成功的两个必要条件:
①1.登录受信任网站A,并在本地生成Cookie。(如果用户没有登录网站A,那么网站B在诱导的时候,请求网站A的api接口时,会提示你登录),且cookies或者session 尚未过期;
②在不登出A的情况下,访问危险网站B(其实是利用了网站A的漏洞)。
这里用户C生成的cookie保证了用户可以处于登录状态,但网站B其实拿不到cookie

CSRF漏洞存在

被攻击者一定要处于登陆状态

诱使用户点击并完成操作

几种常见的CSRF攻击类型

get 型

GET类型的CSRF利用非常简单,只需要一个HTTP,一般会这样利用:

java">< img src="http://bank.example/withdraw?account&=xx&amount=100&to=hacker"  >

在受害者访问含有这个img的页面之后,浏览器会自动向http://bank.example/withdraw?account=xx&amount=100&to=hacker发送一次HTTP请求。bank.example就会收到包含受害者登录信息的一次跨域请求。

post 型

这种类型的CSRF利用起来通常使用的是一个自动提交的表单,如:

java">< form action = "https://bank.example/withdraw" method="POST">
    < input type="hidden" name="account" value="xx" />
    < input type="hidden" name="ammount" value="100" />
    < input type="hidden" name="for" value="hacker" />
< /form>
< script> document.forms[0].submit(); </script>

访问该页面后,表单会自动提交,相当于模拟用户完成了一次POST操作。

POST类型的攻击通常比GET要求更加严格一点,但并不复杂。任何个人网站、博客,被黑客上传页面的网站都有可能是发起攻击的来源,后端接口不能将安全寄托在仅允许POST上面。

链接型

链接类型的CSRF并不常见,比起其他两种用户打开页面就会中招的情况,这种需要用户点击链接才会触发。这种类型通常是在论坛中发布图片中嵌入恶意链接,或者以广告的形式诱导用户中招,攻击者通常会以比较夸张的词语诱骗用户点击,例如:

java"><a href="https://bank.example.com/csrf/withdraw.php?amount=100&to=hacker" target="_blank">
    文章和马伊琍离婚!!!
</a>

由于之前用户已经登录,在登录状态还未过期时,只要用户主动访问上面的这个PHP页面,则攻击成功。

CSRF 的特点

攻击一般发起在第三方网站,而不是被攻击的网站。被攻击的网站无法防止攻击发生。

攻击利用受害者在被攻击网站的登录凭证,冒充受害者提交操作;而不是直接窃取数据。

整个过程攻击者并不能获取到受害者的登录凭证,仅仅是“冒用”。

跨站请求可以用各种方式:图片URL、超链接、CORS、Form提交等等。部分请求方式可以直接嵌入在第三方论坛、文章中,难以进行追踪。

CSRF通常是跨域的,因为外域通常更容易被攻击者掌控。但是如果本域下有容易被利用的功能,比如可以发图和链接的论坛和评论区,攻击可以直接在本域下进行,而且这种攻击更加危险。

CSRF 防护策略

1、 将cookie设置为HttpOnly
2、验证 HTTP Referer 字段;
(Referer:在 HTTP 头中的一个字段,它记录了该 HTTP 请求的来源地址。)
3、 在请求地址中添加 token 并验证;
(Token:服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码。)
4、在 HTTP 头中自定义属性并验证。

CARF token 校验

CSRF的另一个特征是,攻击者无法直接窃取到用户的信息(Cookie,Header,网站内容等),仅仅是冒用Cookie中的信息。而CSRF攻击之所以能够成功,是因为服务器误把攻击者发送的请求当成了用户自己的请求。那么我们可以要求所有的用户请求都携带一个CSRF攻击者无法获取到的Token。服务器通过校验请求是否携带正确的Token来把正常的请求和攻击的请求区分开,这也可以防范CSRF的攻击。

基于CSRF Token的防护策略大致分为三个步骤:
  
1.将CSRF Token输出到页面中

首先,用户打开页面的时候,服务器需要给这个用户生成一个Token,该Token通过加密算法对数据进行加密,一般Token都包括随机字符串和时间戳的组合,显然在提交时Token不能再放在Cookie中了,否则又会被攻击者冒用。因此,为了安全起见Token最好还是存在服务器的Session中,之后在每次页面加载时,使用JS遍历整个DOM树,对于DOM中所有的a和form标签后加入Token。这样可以解决大部分的请求,但是对于在页面加载之后动态生成的HTML代码,这种方法就没有作用,还需要程序员在编码时手动添加Token。
  
2.页面提交的请求携带这个Token

对于GET请求,Token将附在请求地址之后,这样URL就变成 http://url?csrftoken=tokenvalue。而对于 POST请求来说,要在form的最后加上:

java"><input type="hidden" name="csrftoken" value="tokenvalue"/>

3.服务器验证Token是否正确

当用户从客户端得到了Token,再次提交给服务器的时候,服务器需要判断Token的有效性,验证过程是先解密Token,对比加密字符串以及时间戳,如果加密字符串一致且时间未过期,那么这个Token就是有效的。

这种方法要比之前检查Referer或者Origin要安全一些,Token可以在产生并放于Session之中,然后在每次请求时把Token从Session中拿出,与请求中的Token进行比对,但这种方法的比较麻烦的在于如何把Token以参数的形式加入请求。 下面将以Java为例,介绍一些CSRF Token的服务端校验逻辑,代码如下:

java">HttpServletRequest req = (HttpServletRequest)request;
HttpSession s = req.getSession();
// 从sesion中得到csrftoken属性
String sToken = (String)s.getAttribute("csrftoken");
if(sToken == null){
    // 产生新的token放入session中
    sToken = generateToken();
    s.setAttribute("csrftoken",sToken);
    chain.doFilter(request,response);
}else{
    // 从HTTP头中取得csrftoken
    String xhrToken = req.getHeader("csrftoken");
    // 从请求参数中取得csrftoken
    String pToken = req.getParameter("csrftoken");
    if(sToken != null && xhrToken != null && sToken.equals(xhrToken)){
        chain.doFilter(request,response);
    }else if(sToken != null & pToken != null && sToken.equals(pToken)){
        chain.doFilter(request,response);
    }else{
        request.getRequestDispatcher("error.jsp").forward(request,response);
    }
}

总结

Token是一个比较有效的CSRF防护方法,只要页面没有XSS漏洞泄露Token,那么接口的CSRF攻击就无法成功。但是此方法的实现比较复杂,需要给每一个页面都写入Token(前端无法使用纯静态页面),每一个Form及Ajax请求都携带这个Token,后端对每一个接口都进行校验,并保证页面Token及请求Token一致。这就使得这个防护策略不能在通用的拦截上统一拦截处理,而需要每一个页面和接口都添加对应的输出和校验。这种方法工作量巨大,且有可能遗漏。


http://www.niftyadmin.cn/n/1829364.html

相关文章

期货笔记-----不定时更新

1.公司制和会员制期货交易所的主要区别为 公司制交易所以营利为主要目标&#xff0c;会员制通常不以营利为主要目标。 会员制期货交易所&#xff1a;上海期货交易所&#xff0c;郑州商品交易所&#xff0c;大连商品交易所 公司制期货交易所&#xff1a;中国金融期货交易所&…

gpt4实现对摄像头帧缓冲区图像的LAB阈值选择界面(python-opencv)

代码全是GPT4写的&#xff0c;我就提出Prompt和要改的地方而已。 图形界面效果 代码 import cv2 import numpy as np import time from tkinter import * from PIL import Image, ImageTkclass App:def __init__(self, window, window_title, video_source0):self.window wi…

python通过protobuf实现rpc

由于项目组现在用的rpc是基于google protobuf rpc协议实现的&#xff0c;所以花了点时间了解下protobuf rpc。rpc对于做分布式系统的人来说肯定不陌生&#xff0c;对于rpc不了解的童鞋可以自行google&#xff0c;这里只是做个简单的介绍。rpc的主要功能是让分布式系统的实现更为…

redis 协议的简单介绍

zhoulin:/opt/redis307/src:gdb ./redis-server --启动redis的服务端 (gdb) set args /etc/redis_6379.conf --设置gdb参数(gdb) br readQueryFromClient --在该函数地方设置断点1180 nread read(fd, c->querybufqblen, readlen); --从fd中读取来自客户端的查询命令(g…

蓝桥杯---简单的计算器

蓝桥杯---简单的计算器 题目&#xff1a; 问题描述  编程模拟计算器的加、减、乘、除功能&#xff0c;根据用户输入的运算符&#xff0c;对两个数进行运算。(要求switch语句)输入格式  输入只有一行&#xff0c;用空格隔开的运算符和两个运算数&#xff0c;运算符一定是, -…

VC6.0建立控制台程序实现PDA应用

作者&#xff1a;iamlaosong 由于须要&#xff0c;又写起了文本界面的程序&#xff0c;以便PDA通过telnet连上运行。假设是Linuxserver的话。这是非常easy的事&#xff0c;但是用户server是windows server 2003&#xff0c;所以就须要安装telnet服务&#xff0c;开发一个控制台…

zw版【转发·台湾nvp系列Delphi例程】HALCON SetLineStyle1

zw版【转发台湾nvp系列Delphi例程】HALCON SetLineStyle1 procedure TForm1.Button1Click(Sender: TObject);var img : HImageX; rg : HRegionX; w, h : OleVariant; val : OleVariant;begin img : CoHImageX.Create; img.ReadImage(ic); w : img.GetImageSize(h); rg : CoHReg…

[apache]用shell分析网站的访问情况

随着网站正式运行&#xff0c;我们可以通过通用的免费日志分析工具比如awstats获得一些实际访问网站的信息,例如每天ip量&#xff0c;pv量&#xff0c;用户所用的的浏览器&#xff0c;用户所用的操作系统等&#xff0c;但是有时候希望通过手工方式从WEB日志文件中获得一些信息&…