跨站请求伪造
csrf是一种诱导获得身份认证的终端用户执行一个他意想不到的动作的方法,在一个web应用程序。他可以用来指定一个特定的状态改变请求,而不是盗取数据,因为无法获得请求返回的数据。攻击者可以利用社会(社交)工程学,比如发送一个email链接或者聊天,来欺骗受害者执行他们想要的动作。
大多数框架具有内置的CSRF支持,例如 Joomla, Spring, Struts, Ruby on Rails, .NET 等。
csrf可以欺骗受害者来提交一个其未知的请求,该请求继承了他的身份和特权,对于大多数站点,浏览器在做请求时会自动带上与此站点相关的凭证,比如用户的session cookie, ip地址,windows域凭证等,如果用户当前已得到站点的身验证,则站点没有办法区分该请求是否合法。
csrf攻击通常引起在服务器上的状态改变,例如修改受害者的email地址,密码或其他事情,强迫受骗者去检索数据并不利于攻击者, 应为攻击者无法接受response,但是受害者可以。所以csrf攻击的目标是状态更改请求。
有时候可能把csrf攻击存在易受攻击的站点上,这种攻击方式叫存储csrf漏洞。这可以通过简单的存储一个IMG或IFRAME标记到html字段,或者更复杂的跨站脚本攻击来实现。这种漏洞危害性是很大的。
csrf同时也叫xsrf, "sea surf",会话控制,跨站点伪造参考,恶意链接等。
以下方法是无效的:
使用加密cookie:
所有的cookie,即使是加密的,每次请求的时候都会被提交。所有的身份认证令牌(token)都会提交,在请求的时候,即使是被起欺骗的。而且,应用程序仅仅用会话标识符来维系请求和特定的会话对象,会话标识符不会核实用户终端是否打算提交该请求。
只接收post请求:
应用的逻辑执行时可以选择只接收post请求,不要以为攻击者不会构造恶意链接,或者csrf不会被执行,攻击者也会伪造恶意的post请求,比如一个表单请求可以被隐藏在攻击者的网站上,这个表单可以自动被javascript或者受害者无意中执行。
有一些方法用于反csrf工具,但其实这些方法是有缺陷的:
增多步骤处理:
这不是一个能完全预防csrf攻击的注意,只要攻击者能猜测或推断出完成处理中的每个步骤,攻击就是有可能的。
url重写:
这项技术可能看上去对于预防csrf有效,攻击方无法访问受害者的会话ID,但是用户session ID是暴露在URL中,我们可能因此又会产生另一个安全缺陷,人们可以获得sessionID来定位获取session信息。
HTTPS:
https本身并不能预防csrf攻击,但是https应该是被考虑的一个先决条件对于任何值得相信的预防攻击方法。
Examples:
攻击是如何工作的:
有很多方法可以欺骗终端用户从一个web应用读取或者加载信息,为了执行攻击,我们必须明白如何构造一个有效的恶意请求让受骗者执行。比如这样一个例子:A希望通过bank.com这个web应用转100快给B,这个bank.com是易受csrf攻击的,攻击者想欺骗A转100给他自己,攻击者可以做如下步骤:
1.构建一个诱饵url或脚本
2.利用社会工程学的方法欺骗A执行1
GET场景:
如果程序被设计为主要使用GET请求来传递参数和执行动作,钱的转账操作可能简单的描述为如下请求:GET http://bank.com/transfer.do?acct=B&amount=100 HTTP/1.1
M决定利用这个web程序的漏洞来陷害A,M首先构造像上面的URL将转100000快从A到M自己的账号,他可以修改url的一些参数来达到目的:GET http://bank.com/transfer.do?acct=M&amount=100000 HTTP/1.1
M利用社会工程学的一些知识里诱导A打开这个链接,当他登陆了银行应用时。这里通常使用以下几种技术来达到:
1.发送一个不请自来的带有html内容的email
2.植入一个陷阱URL或脚本在页面上看起来像是可以访问的,在受骗者还在银行应用上操作时。
陷阱URL可以伪装成一个普通链接,来鼓励受骗者点击它:
<a href="http://bank.com/transfer.do?acct=MARIA&amount=100000">View my Pictures!</a>
Or as a 0x0 fake image:
<img src="http://bank.com/transfer.do?acct=MARIA&amount=100000" width="0" height="0" border="0">
这个图片标签tag被放在一个email中,A不明真相点击了他,浏览器就会执行他并转账给M
POST场景:
POST和GET之间唯一不同的就是攻击如何被受骗者执行。
举GET的银行例子,现在使用POST方式:
POST http://bank.com/transfer.do HTTP/1.1
acct=BOB&amount=100
这个请求在GET案例中不能被提交,但是可以用FORM tag来被提交:
<form action="<nowiki>http://bank.com/transfer.do</nowiki>" method="POST">
<input type="hidden" name="acct" value="MARIA"/>
<input type="hidden" name="amount" value="100000"/>
<input type="submit" value="View my pictures"/>
</form>
这个表单在用户单击submit按钮时请求,但也可以用JavaScript自动执行:
<body onload="document.forms[0].submit()">
`<form...`
其他HTTP方法:
现在有些web应用api经常使用其他的http方法,例如PUT或者DELETE,假设一个易受攻击的银行系统使用PUT方法提交一个json块参数:
`PUT http://bank.com/transfer.do HTTP/1.1`
`{ "acct":"BOB", "amount":100 }`
这个请求可嵌入javascript中:
<script>
`function put() {`
` var x = new XMLHttpRequest();`
` x.open("PUT","http://bank.com/transfer.do",true);`
` x.setRequestHeader("Content-Type", "application/json"); `
` x.send(JSON.stringify({"acct":"BOB", "amount":100})); `
`}`
</script>
<body onload="put()">
幸运的是,这个请求浏览器将不会被执行由于同源策略(跨域问题)的限制。这个限制在默认情况下是有用的,除非目标web明白打开来自攻击者(或所有人)的源带有CORS头打开跨源请求:
Access-Control-Allow-Origin: *
相关攻击:
XSS跨站脚本
XSHM跨站历史记录操作
相关建议:
1.增加预请求随机值到url和所有表单,除了标准会话。这涉及到表单key(form keys)。许多框架(例如,drupal.org 4.7.4+
)有或者开始包含这种保护“built-in”到每个表单,开发者无需重新编写这种保护措施。
2.增加一个哈希值(会话ID,函数名,服务器秘钥)到所有表单
3。对于.NET,将会话标识符添加到具有MAC的ViewState
4.检查客户端的http请求头中referrer报文头可预防csrf攻击,确保http请求时来自真实原始站点而非其他源点。由于内存限制,经常看到在嵌入式网络硬件上使用引用头检查。
XSS可被用于同时绕过referer和token检查,例如,samy萨米蠕虫病毒使用XHR获得csrf token来伪造请求
即使csrf攻击对于web应用很难防御,当访问到一个设计糟糕不够安全的站点时,用户可以注销该网站,访问另一个站点时,以自我保护他们的账户。或在关闭每一个浏览器前清除他们的浏览器cookies。
dvwa csrf练习:
low:直接拷贝修改密码的链接,修改关键值请求即可,服务未做任何防护措施。
medium:直接修改关键值请求不可行,对比发现对referer做了限制,所以我们只需对referer做伪造即可。
high:服务返回了hidden类型的token给浏览器,所以请求中需要带回token,我们可以伪造一个相似的银行页面促使受骗者打开,但是伪造页面和源页面不是在同一个地址上,给予跨域限制,无法获取源页面的token,除非源页面主动发送消息给伪造页面。不过可以通过将攻击代码注入到源服务器中实施攻击,利用xss漏洞获取anti-csrf token。
impossible:该级别使用了pdo技术防御sql注入,而csrf则要求输入原始密码,在不知道原始密码的情况下,无法执行修改密码的攻击。