跨站请求伪造(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. [转载]python os.path模块

    os.path模块主要用于文件的属性获取,在编程中经常用到,以下是该模块的几种常用方法.更多的方法可以去查看官方文档:http://docs.python.org/library/os.path.ht ...

  2. javascript中的基本数据类型

    在javascipt中有五大基本数据类型,列表如下: 1.数字 他们又又包括(正负整数,浮点数)十进制数,十六进制数与八进制数,指数和特殊数值NaN,(Infinity,-Infinity)正负无穷 ...

  3. asp.net中后台javaScrip的使用

    ClientScriptManager csm = Page.ClientScript;        //Script标记靠近<form>标签        //csm.Register ...

  4. MySQL5.7.9免安装版配置方法

    1. 解压MySQL压缩包    将下载的MySQL压缩包解压到自定义目录下,我的解压目录是:    "D:\Program Files\mysql-5.7.9-win32"    ...

  5. opencv之图像膨胀

    #include <cv.h> #include <highgui.h> void main() { IplImage* src; IplImage*dst; src=cvLo ...

  6. C#中调用WIN32的API

    最近在学习C#中的GDI部分,本来尝试编写一个字幕控件(其实还是用label比较合适),但是发现控件中用GDI将整个控件粉刷貌似不行(应该是我水平不行),所以就去捣鼓了下WIN32的DLL,发现用AP ...

  7. C# 进销存系统开发框架

    C/S系统开发框架-企业版 V4.0 (Enterprise Edition) 简介: http://www.csframework.com/cs-framework-4.0.htm 视频下载: 百度 ...

  8. jquery cleditor 光标经常点不进去问题解决方法 bootstrap 富文本框 控件

    cleditor 光标点不进去,原因是内嵌的html代码段 body没有赋值默认高度. 解决方法1.赋值options.bodyStyle  设置min-height值.缺点:不能跟随设备更新最低高度 ...

  9. 利用HTML5分片上传超大文件

    在网页中直接上传大文件一直是个比较头疼的问题,主要面临的问题一般包括两类:一是上传时间长中途一旦出错会导致前功尽弃:二是服务端配置复杂,要考虑接收超大表单和超时问题,如果是托管主机没准还改不了配置,默 ...

  10. oracle timestamp的转换

    select to_char(stime,'yyyy-mm-dd HH24:MI:ss.ff3') from e_bmp_log_operation t where t.sdetail like '% ...