一、什么是CSRF漏洞?
CSRF(Cross-Site Request Forgery,跨站请求伪造)是一种网络攻击,它利用受害者在受信任网站上的已认证会话,来执行非预期的行动。这种攻击的核心在于,攻击者能够诱使受害者的浏览器向一个他们已经登录的网站发送恶意构造的请求,而该网站会错误地认为这个请求是用户有意发起的。
1.1原理
当用户成功登录一个网站时,服务器会返回该用户的“身份证”,也就是cookie。当用户后续进行操作时,浏览器会自动添加上这个cookie,服务器收到数据包后就会对cookie进行验证,确保是用户进行的操作。攻击者伪造一个网站,通过钓鱼等手段使受害者访问这个网站,如果受害者此时正在访问有csrf的网站,当用户点击假网站的按钮时,浏览器就会将该请求带上cookie,发送给服务端,而此时服务端认为是用户的操作。
二、实际攻击例子
场景设定
假设有一个在线银行系统 bank.example.com
,它存在一个未修复的CSRF漏洞。用户可以通过访问 /updateprofile.php
页面来更新他们的个人资料,但该页面没有适当的CSRF防护机制。
攻击准备
- 创建恶意网站:攻击者首先创建了一个看似合法的网站,可能是模仿了银行的登录界面或提供某种“安全更新”服务的页面。
- 构造CSRF攻击向量:在恶意网站中嵌入一个HTML表单或者通过JavaScript自动提交的代码,就像之前讨论过的那样。这个表单的目标是银行的
/updateprofile.php
,并且包含了攻击者想要更改的信息,例如用户的电子邮件地址、密码提示问题等。 - 伪装钓鱼邮件:攻击者设计了一封看起来像是来自银行的紧急通知邮件,告知用户有关账户的安全问题,并要求他们立即采取行动。
钓鱼邮件内容示例
主题: 紧急:您的银行账户需要立即验证!亲爱的客户,我们检测到您的账户可能存在异常活动。为了确保您的账户安全,请立即点击下面的链接进行验证。[立即验证账户] (http://malicious-site.example)如果您最近没有尝试过任何更改,请尽快执行此操作以保护您的账户。感谢您对我们服务的支持。祝好,
Bank Example 客户服务团队
CSRF攻击向量(恶意网站中的HTML/JavaScript)
<html><body onload="document.getElementById('csrfForm').submit()"><form id="csrfForm" action="https://bank.example.com/updateprofile.php" method="POST"><input type="hidden" name="email" value="attacker@example.com" /><input type="hidden" name="passhint" value="What is the capital of France?" /><!-- 其他需要修改的字段 --></form><p>请稍候,正在验证您的账户...</p></body>
</html>
在这个例子中,当受害者点击了钓鱼邮件中的链接并访问了恶意网站时,页面会自动加载并提交一个指向银行服务器的表单请求。如果受害者在同一浏览器中已经登录到了真正的银行网站,那么这个请求将会携带有效的会话Cookie,从而导致银行服务器认为这是一个合法的请求,并按照提供的数据更新受害者的账户信息。
三、靶场实验
这次实验使用OWASP发行的Broken Web Application进行演示。
https://sourceforge.net/projects/owaspbwa/
点击下载,在vmware中打开虚拟机文件即可。
在浏览器访问提示的网址
选择GETBOO
点击右上角的"Log In",使用user,user登录
点击右上角的“Settings”
选择“Modify account information”功能,这里可以修改用户邮箱
开启bp抓包之后,点击"Updates",可以看到需要修改的邮箱账号
右键利用工具生成POC
修改需要绑定的邮箱,这里改为“kimjiwon”
复制生成的HTML,在桌面新建一个HTML文件,放进去
使用你打开靶场的浏览器打开(不同浏览器无法利用cookie),这个页面相当于恶意网站
点击按钮,发现无意中发送了修改邮箱的请求
到此,攻击者已经实现攻击目的了,在受害者没有察觉的情况下修改了邮箱。利用这种手段,攻击者可以执行其他操作如修改密码等。
四、防御措施
1. 使用CSRF令牌
- 生成唯一的CSRF令牌:对于每个用户会话或表单提交,服务器应该生成一个独一无二的、不可预测的CSRF令牌。
- 将令牌嵌入到表单中:这个令牌作为一个隐藏字段包含在每个需要保护的HTML表单中。
- 验证令牌:当接收到来自客户端的POST请求时,服务器必须检查该请求是否包含了正确的CSRF令牌,并且它与当前用户的会话相匹配。如果不匹配,则拒绝处理该请求。
2. 设置SameSite Cookies属性
- 启用SameSite属性:通过设置Cookies的
SameSite
属性为Strict
或Lax
,可以限制Cookies只在同站请求中发送。这有效地阻止了大多数类型的CSRF攻击,因为跨站请求不会附带敏感的认证信息。SameSite=Strict
:Cookies仅在直接导航(如用户手动输入URL或点击书签)时才会被发送。SameSite=Lax
:允许某些跨站顶级导航请求(如GET请求)发送Cookies,但禁止通过iframe等嵌入式上下文中的跨站请求发送Cookies。
3. 检查Referer和Origin头部
- 验证来源:检查refer是否是第三方网站发起的。尽管不是最可靠的防御机制,因为refer的内容可以被修改,但检查HTTP请求中的
Referer
或Origin
头部可以帮助识别潜在的CSRF攻击。合法请求通常会有正确的来源信息,而恶意请求可能会缺少或有不匹配的来源信息。
4. 使用框架内置的CSRF防护功能
- 利用现有工具:许多现代Web开发框架(如Django、Rails、ASP.NET Core等)都内置了CSRF防护功能。确保正确配置并使用这些框架提供的安全特性。
5. 实现基于用户交互的二次确认
- 增加额外步骤:对于特别敏感的操作,比如更改密码或电子邮件地址,要求用户提供额外的验证信息,如重新输入密码或通过短信验证码进行二次确认。