跨站请求伪造(CSRF)是一种允许攻击者通过受害者发送任意HTTP请求的一类攻击方法。此处所指的受害者是一个不知情的同谋,所有的伪造请求都由他发起,而不是攻击者。这样,很你就很难确定哪些请求是属于跨站请求伪造攻击。事实上,如果没有对跨站请求伪造攻击进行特意防范的话,你的应用很有可能是有漏洞的。

请看下面一个简单的应用,它允许用户购买钢笔或铅笔。界面上包含下面的表单:

01 <form action="buy.php" method="POST">
02   <p>
03   Item:
04   <select name="item">
05     <option name="pen">pen</option>
06     <option name="pencil">pencil</option>
07   </select><br />
08   Quantity: <input type="text" name="quantity" /><br />
09   <input type="submit" value="Buy" />
10   </p>
11 </form>

一个攻击者会首先使用你的应用以收集一些基本信息。例如,攻击者首先访问表单并发现两个表单元素item及quantity,他也同时知道了item的值会是铅笔或是钢笔。

下面的buy.php程序处理表单的提交信息:

01 <?php
02   
03   session_start();
04   $clean = array();
05   
06   if (isset($_REQUEST['item'] && isset($_REQUEST['quantity']))
07   {
08     /* Filter Input ($_REQUEST['item'], $_REQUEST['quantity']) */
09   
10     if (buy_item($clean['item'], $clean['quantity']))
11     {
12       echo '<p>Thanks for your purchase.</p>';
13     }
14     else
15     {
16       echo '<p>There was a problem with your order.</p>';
17     }
18   }
19   
20 ?>

攻击者会首先使用这个表单来观察它的动作。例如,在购买了一支铅笔后,攻击者知道了在购买成功后会出现感谢信息。注意到这一点后,攻击者会尝试通过访问下面的URL以用GET方式提交数据是否能达到同样的目的:

http://store.example.org/buy.php?item=pen&quantity=1

如果能成功的话,攻击者现在就取得了当合法用户访问时,可以引发购买的URL格式。在这种情况下,进行跨站请求伪造攻击非常容易,因为攻击者只要引发受害者访问该URL即可。

虽然有多种发起跨站请求伪造攻击的方式,但是使用嵌入资源如图片的方式是最普遍的。为了理解这个攻击的过程,首先有必要了解浏览器请求这些资源的方式。

当你访问http://www.google.com,你的浏览器首先会请求这个URL所标识的资源。你可以通过查看该页的源文件(HTML)的方式来看到该请求的返回内容。在浏览器解析了返回内容后发现了Google的标志图片。这个图片是以HTML的img标签表示的,该标签的src属性表示了图片的URL。浏览器于是再发出对该图片的请求,以上这两次请求间的不同点只是URL的不同。

根据上面的原理,跨站请求伪造攻击可以通过img标签来实现。考虑一下如果访问包括下面的源代码的网页会发生什么情况:

由于buy.php脚本使用$_REQUEST而不是$_POST,这样每一个只要是登录在store.example.org商店上的用户就会通过请求该URL购买50支铅笔。

跨站请求伪造攻击的存在是不推荐使用$_REQUEST的原因之一。

当请求一个图片时,某些浏览器会改变请求头部的Accept值以给图片类型以一个更高的优先权。需要采用保护措施以防止这种情况的发生。

你需要用几个步骤来减轻跨站请求伪造攻击的风险。一般的步骤包括使用POST方式而不是使用GET来提交表单,在处理表单提交时使用$_POST而不是$_REQUEST,同时需要在重要操作时进行验证(越是方便,风险越大,你需要求得方便与风险之间的平衡)。

任何需要进行操作的表单都要使用POST方式。在RFC 2616(HTTP/1.1传送协议,译注)的9.1.1小节中有一段描述:

“特别需要指出的是,习惯上GET与HEAD方式不应该用于引发一个操作,而只是用于获取信息。这些方式应该被认为是‘安全’的。客户浏览器应以特殊的方式,如POST,PUT或DELETE方式来使用户意识到正在请求进行的操作可能是不安全的。”

最重要的一点是你要做到能强制使用你自己的表单进行提交。尽管用户提交的数据看起来象是你表单的提交结果,但如果用户并不是在最近调用的表单,这就比较可疑了。请看下面对前例应用更改后的代码:

1 <?php
2   
3   session_start();
4   $token = md5(uniqid(rand(), TRUE));
5   $_SESSION['token'] = $token;
6   $_SESSION['token_time'] = time();
7   
8 ?>

表单:

01 <form action="buy.php" method="POST">
02   <input type="hidden" name="token" value="<?php echo $token; ?>" />
03   <p>
04   Item:
05   <select name="item">
06     <option name="pen">pen</option>
07     <option name="pencil">pencil</option>
08   </select><br />
09   Quantity: <input type="text" name="quantity" /><br />
10   <input type="submit" value="Buy" />
11   </p>
12 </form>

通过这些简单的修改,一个跨站请求伪造攻击就必须包括一个合法的验证码以完全模仿表单提交。由于验证码的保存在用户的session中的,攻击者必须对每个受害者使用不同的验证码。这样就有效的限制了对一个用户的任何攻击,它要求攻击者获取另外一个用户的合法验证码。使用你自己的验证码来伪造另外一个用户的请求是无效的。

该验证码可以简单地通过一个条件表达式来进行检查:

1 <?php
2   
3   if (isset($_SESSION['token']) && $_POST['token'] == $_SESSION['token'])
4   {
5     /* Valid Token */
6   }
7   
8 ?>

你还能对验证码加上一个有效时间限制,如5分钟:

01 <?php
02   
03   $token_age = time() - $_SESSION['token_time'];
04   
05   if ($token_age <= 300)
06   {
07     /* Less than five minutes has passed. */
08   }
09   
10 ?>

通过在你的表单中包括验证码,你事实上已经消除了跨站请求伪造攻击的风险。可以在任何需要执行操作的任何表单中使用这个流程。

尽管我使用img标签描述了攻击方法,但跨站请求伪造攻击只是一个总称,它是指所有攻击者通过伪造他人的HTTP请求进行攻击的类型。已知的攻击方法同时包括对GET和POST的攻击,所以不要认为只要严格地只使用POST方式就行了。

PHP安全编程:跨站请求伪造CSRF的防御(转)的更多相关文章

  1. 跨站请求伪造(CSRF)-简述

    跨站请求伪造(CSRF)-简述 跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 ...

  2. 跨站请求伪造(CSRF)攻击原理解析:比你所想的更危险

    跨站请求伪造(CSRF)攻击原理解析:比你所想的更危险 跨站请求伪造(Cross-Site Request Forgery)或许是最令人难以理解的一种攻击方式了,但也正因如此,它的危险性也被人们所低估 ...

  3. django之跨站请求伪造csrf

    目录 跨站请求伪造 csrf 钓鱼网站 模拟实现 针对form表单 ajax请求 csrf相关的两个装饰器 跨站请求伪造 csrf 钓鱼网站 就类似于你搭建了一个跟银行一模一样的web页面 , 用户在 ...

  4. 跨站请求伪造 CSRF / XSRF<一:介绍>

    跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一 ...

  5. 跨站请求伪造CSRF(Cross-site request forgery)

    CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站 ...

  6. 跨站请求伪造(csrf)中间件整理

    一. CSRF中间件 字面意思跨站请求伪造; 即模仿个请求朝服务器发送,django中对跨站伪造的请求有相应的校验 from django.views.decorators.csrf import c ...

  7. 安全性测试入门 (三):CSRF 跨站请求伪造攻击和防御

    本篇继续对于安全性测试话题,结合DVWA进行研习. CSRF(Cross-site request forgery):跨站请求伪造 1. 跨站请求伪造攻击 CSRF则通过伪装成受信任用户的请求来利用受 ...

  8. 跨站请求伪造(csrf)的防护手段

    CSRF CSRF全拼为Cross Site Request Forgery,译为跨站请求伪造. CSRF指攻击者盗用了你的身份,以你的名义发送恶意请求. 造成的问题:个人隐私泄露以及财产安全. CS ...

  9. 跨站请求伪造CSRF:攻击与防御

    CSRF是什么         (Cross Site Request Forgery, 跨站域请求伪造)是一种网络的攻击方式,它在 2007 年曾被列为互联网 20 大安全隐患之一,也被称为&quo ...

随机推荐

  1. amf0解释一下

    就简单记录一下省了以后忘了,amf0其实就几种数据格式的网络传输格式,比如数字,字符串,这些格式在传输的时候他给单独序列化了一下,主要支持以下这些: #define AMF0_NUMBER ((uin ...

  2. APP被Rejected 的各种原因翻译(转)

    原文:http://www.cnblogs.com/sell/archive/2013/02/16/2913341.html Terms and conditions(法律与条款) 1.1 As a ...

  3. const关键字与指针

    const与指针在一起的几种情况. const int *p1; //表示p1本身不是const,指向的变量是const. const *int p2; //语法错误 int const *p3; / ...

  4. android 学习第一步

    今天是2015年7月24号,今年下半年的主要学习方向是android,学习的目标是做出3个或以上的有实用价值的app.

  5. [转载]网络编辑必知常识:什么是PV、UV和PR值 zz

    1.什么是pv PV(page view),即页面浏览量,或点击量;通常是衡量一个网络新闻频道或网站甚至一条网络新闻的主要指标. 高手对pv的解释是,一个访问者在24小时(0点到24点)内到底看了你网 ...

  6. 用链表解决if语句过多的问题(C/C++实现)

    起因 http://www.cnblogs.com/code-style/p/3499408.html 设计模式的解决方案(基于python语言) http://www.cnblogs.com/cod ...

  7. 2D地图随机生成

    2D地图随机生成基础绘图 海陆分布

  8. cf C. Arithmetic Progression

    http://codeforces.com/contest/382/problem/C 题意:给你n个数,然后让你添加一个数使得n+1个数能形成这样的规律,a[1]-a[0]=a[2]-a[1]=a[ ...

  9. iOS Developer Libray (中文版)-- About Objective-C

    该篇是我自己学习iOS开发时阅读文档时随手记下的翻译,有些地方不是很准确,但是意思还是对的,毕竟我英语也不是很好,很多句子无法做到准确的字词翻译,大家可以当做参考,有错误欢迎指出,以后我会尽力翻译的更 ...

  10. ios入门之c语言篇——基本函数——1——随机数生成

    1.随机数函数 参数返回值解析: 参数: a:int,数字范围最小值: b:int,数字范围最大值: 返回值: 1:闰年: 0:非闰年: 备注: a-b的绝对值不能超过int的最大值(65535); ...