CSRF漏洞原理攻击与防御

CSRF(Cross-site request forgery)跨站请求伪造:也被称为“One Click Attack”或者Session Riding, 通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。尽管听起来像跨站脚本(XSS),但它与XSS非 常不同,XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。

与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被 认为比XSS更具危险性。

csrf漏洞的成因就是网站的cookie在浏览器中不会过期,只要不关闭浏览器或者退出登录,那以后只要 是访问这个都网站,会默认你已经登录的状态。而在这个期间,攻击者发送了构造好的csrf脚本或包含 csrf脚本的链接,可能会执行一些用户不想做的功能(比如是添加账号等)。

CSRF可以做什么?

你这可以这么理解CSRF攻击:

攻击者盗用了你的身份,以你的名义发送恶意请求。

CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账......

造成的问题包括:个人隐私泄露以及财产安全。

想要深入理解CSRF的攻击特性我们有必要了解一下网站Session的工作原理。

Session大家都不陌生,无论是用.net还是PHP开发过网站的程序员都肯定用过Session对象,然而 Session它是如何工作的呢?如果我们把浏览器的Cookie禁用了,大家认为Session还能正常工作吗? 答案是否定的。

在这里举个简单的例子帮助大家理解Session。比如我买了一张高尔夫俱乐部的会员卡,俱乐部给了我一 张带有卡号的会员卡。我能享受哪些权利呢?如果我是高级会员卡可以打19洞和后付费喝饮料,而初级 会员卡只能在练习场挥杆。我的个人资料都是保存在高尔夫俱乐部的数据库里,我每次去高尔夫俱乐部 只需要出示这张高级会员卡,俱乐部就知道我是谁了,并且为我服务了。 因此我们的高级会员卡卡号 相当于保存在Cookie的Sessionid;而我的高级会员卡权利和个人信息就相当于服务端的Session对象。

我们知道Http是无状态的协议,它不要求浏览器在每次请求中标明客户端自己的身份,并且浏览器以及 服务器之间并没有保持一个持久性的连接用于多个页面之间的访问。为了维持web应用程序状态的问 题,每次Http请求都会将本域下的所有Cookie作为Http请求头的一部分发送给服务端,服务器端就可以 根据请求中的Cookie所存放的Sessionid去Session对象中找到该会员资料了。

我们理解了Session的工作机制后,CSRF也就很容易理解了。CSRF攻击就相当于攻击用户复制了我的高 级会员卡,然后攻击用户就可以拿着这张假冒的高级会员卡去高尔夫俱乐部打19洞,享受美味的饮料, 而我这个受害者在月底就会收到高尔夫俱乐部的账单。

CSRF原理:

CSRF攻击过程有以下两个重点:

1.目标用户已经登录了网站,能够执行网站的功能

2.目标用户访问了攻击者构造的URL

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的机制之后,危害性我相信大家已经不言而喻了,我可以伪造某一个用户的身份给其好友发送 垃圾信息,这些垃圾信息的超链接可能带有木马程序或者一些欺骗信息(比如借钱之类的),如果CSRF 发送的垃圾信息还带有蠕虫链接的话,那些接收到这些有害信息的好友万一打开私信中的链接就也成为 了有害信息的散播着,这样数以万计的用户被窃取了资料种植了木马。整个网站的应用就可能在瞬间崩 溃,用户投诉,用户流失,公司声誉一落千丈甚至面临倒闭。曾经在MSN上,一个美国的19岁的小伙子 Samy利用CSS的background漏洞几小时内让100多万用户成功的感染了他的蠕虫,虽然这个蠕虫并没有 破坏整个应用,只是在每一个用户的签名后面都增加了一句“Samy 是我的偶像”,但是一旦这些漏洞被恶 意用户利用,后果将不堪设想,同样的事情也曾经发生在新浪微博。

相关举例:

受害者Bob 在银行有一笔存款,通过对银行的网站发送请求 “http://bank.example/withdraw?account=bob&amount=1000000&for=bob2”可以使 Bob把1000000 块的存款转到Bob2的账号下。通常情况下,该请求发送到网站后,服务器会先验证该请求是否来自一个 合法的Session,并且该Session的用户Bob已经成功登陆。黑客Hacker自己在该银行也有账户,他知道 上文中的URL可以把钱进行转帐操作。 Hacker可以自己发送一个请求给银行: http://bank.example/withdrawaccount=bob&amount=1000000&for=Hacker。 但是这个请求来自Hacker而非 Bob,他不能通过安全认证,因此该请求不会起作用。这时,Hacker想 到使用CSRF的攻击方式,他先自己做一个网站,在网站中放入如下代码: src=“http://bank.example/withdrawaccount=bob&amount=1000000&for=Hacker”,并且通过广告 等诱使 Bob 来访问他的网站。当Bob访问该网站时,上述URL就会从Bob的浏览器发向银行,而这个请 求会附带Bob浏览器中的 Cookie 一起发向银行服务器。大多数情况下,该请求会失败,因为他要求Bob 的认证信息。但是,如果Bob当时恰巧刚访问他的银行后不久,他的浏览器与银行网站之间的Session尚 未过期,浏览器的Cookie之中含有Bob的认证信息。这时,悲剧发生了,这个URL请求就会得到响应, 钱将从Bob的账号转移到Hacker的账号,而Bob当时毫不知情。等以后Bob发现账户钱少了,即使他去 银行查询日志,他也只能发现确实有一个来自于他本人的合法请求转移了资金,没有任何被攻击的痕 迹。而Hacker则可以拿到钱后逍遥法外。

CSRF检测:

检测CSRF漏洞是一项比较繁琐的工作,最简单的方法就是抓取一个正常请求的数据包,去掉Referer字 段后再重新提交,如果该提交还有效,那么基本上可以确定存在CSRF漏洞。 随着对CSRF漏洞研究的不 断深入,不断涌现出一些专门针对CSRF漏洞进行检测的工具,如CSRFTester,CSRF Request Builder 等。以CSRFTester工具为例,CSRF漏洞检测工具的测试原理如下:使用CSRFTester进行测试时,首先 需要抓取我们在浏览器中访问过的所有链接以及所有的表单等信息,然后通过在CSRFTester中修改相应 的表单等信息,重新提交,这相当于一次伪造客户端请求。如果修改后的测试请求成功被网站服务器接 受,则说明存在CSRF漏洞,当然此款工具也可以被用来进行CSRF攻击。

CSRF防御:

目前防御 CSRF 攻击主要有三种策略:

  • 验证 HTTP Referer 字段;
  • 在请求地址中添加token并验证;
  • 在HTTP头中自定义属性并验证。

验证Referer

根据 HTTP 协议,在HTTP头中有一个字段叫Referer,它记录了该 HTTP 请求的来源地址。在通常情况 下,访问一个安全受限页面的请求来自于同一个网站,比如需要访问

http://bank.example/withdraw?account=bob&amount=1000000&for= Hacker,

用户必须先登陆bank.example,然后通过点击页面上的按钮来触发转账事件。这时,该转帐请求的 Referer值就会是转账按钮所在的页面的URL,通常是以bank.example域名开头的地址。而如果黑客要 对银行网站实施 CSRF 攻击,他只能在他自己的网站构造请求,当用户通过黑客的网站发送请求到银行 时,该请求的 Referer 是指向黑客自己的网站。因此,要防御CSRF攻击,银行网站只需要对于每一个转 账请求验证其Referer值,如果是以bank.example开头的域名,则说明该请求是来自银行网站自己的请 求,是合法的。如果Referer是其他网站的话,则有可能是黑客的CSRF攻击,拒绝该请求。

这种方法的显而易见的好处就是简单易行,网站的普通开发人员不需要操心CSRF的漏洞,只需要在最后 给所有安全敏感的请求统一增加一个拦截器来检查Referer的值就可以。特别是对于当前现有的系统,不 需要改变当前系统的任何已有代码和逻辑,没有风险,非常便捷。

然而,这种方法并非万无一失。Referer的值是由浏览器提供的,虽然 HTTP协议上有明确的要求,但是 每个浏览器对于Referer的具体实现可能有差别,并不能保证浏览器自身没有安全漏洞。使用验证 Referer 值的方法,就是把安全性都依赖于第三方(即浏览器)来保障,从理论上来讲,这样并不安 全。事实上,对于某些浏览器,比如 IE6 或 FF2,目前已经有一些方法可以篡改 Referer值。如果 bank.example网站支持 IE6 浏览器,黑客完全可以把用户浏览器的Referer值设为以bank.example域名 开头的地址,这样就可以通过验证,从而进行 CSRF 攻击。

<?php
header("Content-type:text/html;charset=utf-8");
// 如果没有token, 怎么保证请求是合法的呢?
// 请求头里面有一个字段: referer, 专门用于记录请求来源
// http://www.s285.com/csrf/referer.php
$referer_conf = "http://www.s285.com/csrf/referer.php";
// 获取请求过来的referer
$request_referer = $_SERVER['HTTP_REFERER'];
// 对referer进行对比
if ($referer_conf != $request_referer){
die("请求不合法!");
}
echo "进来啦!";
// 有些浏览器,是不会自带referer的,还有一些浏览器referer可以修改。
// 就会造成一些问题,referer判断不准确

添加token:

CSRF 攻击之所以能够成功,是因为黑客可以完全伪造用户的请求,该请求中所有的用户验证信息都是存 在于Cookie中,因此黑客可以在不知道这些验证信息的情况下直接利用用户自己的Cookie来通过安全验 证。要抵御CSRF,关键在于在请求中放入黑客所不能伪造的信息,并且该信息不存在于Cookie之中。可 以在HTTP请求中以参数的形式加入一个随机产生的token,并在服务器端建立一个拦截器来验证这个 token,如果请求中没有token或者token内容不正确,则认为可能是CSRF攻击而拒绝该请求。 这种方法 要比检查Referer要安全一些,token可以在用户登陆后产生并放于session之中,然后在每次请求时把 token从session中拿出,与请求中的token进行比对,但这种方法的难点在于如何把token以参数的形式 加入请求。对于 GET 请求,token将附在请求地址之后,这样 URL 就变成 http://url?csrftoken=tokenv alue。 而对于 POST 请求来说,要在 form 的最后加上这样就把 token 以参数的形式加入请求了。

表单令牌:

<?php
header("Content-type:text/html;charset=utf-8");
// 开启session
session_start();
// 在配置文件里面有一个key
$key = "qwaerfewasfasfadgkljdgslkdfjiadfjads";
// 生成token
$token = md5(rand(1, 100000).$key);
// 存放到session中
$_SESSION['token'] = $token;
?>
<form action="./edit_back.php" method="post">
<label>姓名:</label><input type="text" name="username">
<br><br>
<label>年龄:</label><input type="text" name="userAge">
<br><br>
<label>地址:</label><input type="text" name="userAddress">
<input type="hidden" name="token" value="<?=$token?>">
<br><br>
<input type="submit">
</form>

后台验证:

<?php
header("Content-type:text/html;charset=utf-8");
// 开启session
session_start();
// 获取表单的令牌
$token = $_POST['token'];
// 获取session中的token
$session_token = $_SESSION['token'];
echo $token."~~~".$session_token;
// 判断令牌
if ($token != $session_token){
die('提交的数据有问题!');
}
echo "修改成功!";

自定义属性进行校验jwt: Json web token主要是用于前后端分离的项目。

CSRF核心是借COOKIE,XSS核心是偷COOKIE

怎么防止别人借用COOKIE? 怎么才能不让别人借COOKIE? 所有的和认证信息相关的一些数据,都不存放在COOKIE中, 全部放在请求头Authorization这个字段 中。 这个字段(Authorization)里面存放的就是:用户ID,用户的角色........ JWT: 会对传输的数据进行加密, 如果要解密,需要服务端私钥的。 就算JWT被劫持,被修改, 在服务端校验的时候依然通不过

  • 40
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CSRF(Cross-Site Request Forgery)跨站请求伪造是一种常见的Web安全漏洞攻击者可以盗用用户的身份,以用户的名义发送恶意请求。造成的危害包括但不限于:修改用户信息、发邮件、发微博、加好友、发私信、甚至财产操作等。 CSRF攻击原理攻击者构造出一个后端请求地址,诱导用户点击或者通过其他方式自动发起请求。如果被攻击用户在网站中已经登录过,那么该请求会默认携带用户的登录凭证,后端服务器就会根据请求的内容进行相应的操作,如修改用户信息等。 下面是一个简单的示例,演示了在不使用CSRF防御措施的情况下,如何利用CSRF漏洞进行攻击: 后端代码: ```python @app.route('/change_password', methods=['POST']) def change_password(): username = request.form.get('username') new_password = request.form.get('new_password') # 设置新密码 # ... return 'Password changed successfully!' ``` 前端代码: ```html <html> <head> <title>Change Password</title> </head> <body> <form action="http://www.example.com/change_password" method="POST"> <input type="hidden" name="username" value="admin"> <input type="hidden" name="new_password" value="hacked"> <input type="submit" value="Change Password"> </form> </body> </html> ``` 攻击者可以在自己的网站中构造一个类似于上面的表单,然后诱导用户点击提交按钮。当用户点击提交按钮后,浏览器会自动向`http://www.example.com/change_password`地址发送POST请求,其中会包含攻击者构造的username和new_password参数。由于用户已经登录过`www.example.com`网站,所以请求会默认携带用户的登录凭证,后端服务器会根据请求的内容进行相应的操作,如修改用户密码等。 在实际应用中,为了防止CSRF攻击,我们可以在后端代码中添加CSRF令牌验证: ```python from flask_wtf.csrf import CSRFProtect app = Flask(__name__) csrf = CSRFProtect(app) @app.route('/change_password', methods=['POST']) @csrf.protect() def change_password(): username = request.form.get('username') new_password = request.form.get('new_password') # 设置新密码 # ... return 'Password changed successfully!' ``` 在前端代码中,我们可以使用`csrf_token`字段来传递CSRF令牌: ```html <html> <head> <title>Change Password</title> </head> <body> <form action="http://www.example.com/change_password" method="POST"> <input type="hidden" name="username" value="admin"> <input type="hidden" name="new_password" value="hacked"> <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"> <input type="submit" value="Change Password"> </form> </body> </html> ``` 在后端代码中,`@csrf.protect()`装饰器会自动验证CSRF令牌的有效性,如果验证失败,则会返回`400 Bad Request`错误。在前端代码中,我们使用`{{ csrf_token() }}`来生成CSRF令牌,并将其作为隐藏字段传递给后端。这样,即使攻击者构造了类似的表单,由于没有正确的CSRF令牌,后端服务器也会拒绝处理该请求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值