是一种容许攻击者经过受害者发送任意HTTP请求的一类攻击方法。此处所指的受害者是一个不知情的同谋,全部的伪造请求都由他发起,而不是攻击者。这样,很你就很难肯定哪些请求是属于跨站请求伪造攻击php
以下表单浏览器
<form action="buy.php" method="POST"> <p> Item: <select name="item"> <option name="pen">pen</option> <option name="pencil">pencil</option> </select><br /> Quantity: <input type="text" name="quantity" /><br /> <input type="submit" value="Buy" /> </p> </form>
php请求处理安全
<?php session_start(); $clean = array(); if (isset($_REQUEST['item'] && isset($_REQUEST['quantity'])) { /* Filter Input ($_REQUEST['item'], $_REQUEST['quantity']) */ if (buy_item($clean['item'], $clean['quantity'])) { echo '<p>Thanks for your purchase.</p>'; } else { echo '<p>There was a problem with your order.</p>'; } } ?>
攻击者尝试使用get方式:http://store.example.org/buy.php?item=pen&quantity=1
若是能成功的话,攻击者若是取得了当合法用户访问时,能够引起购买的URL格式。在这种状况下,进行跨站请求伪造攻击很是容易,由于攻击者只要引起受害者访问该URL便可服务器
攻击者并不须要取得用户受权cookie
用户再访问其余网站的时候,若是这个网站引导用户发起了上面的请求,浏览器会带上用户相关的cookie,至关于非法网站取得了用户受权。当你访问http://www.google.com,你的浏览器首先会请求这个URL所标识的资源。你能够经过查看该页的源文件(HTML)的方式来看到该请求的返回内容。在浏览器解析了返回内容后发现了Google的标志图片。这个图片是以HTML的img标签表示的,该标签的src属性表示了图片的URL。浏览器因而再发出对该图片的请求,以上这两次请求间的不一样点只是URL的不一样。session
根据上面的原理,跨站请求伪造攻击能够经过img标签来实现。考虑一下若是访问包括下面的源代码的网页会发生什么状况:
<img src="http://store.example.org/buy.php?item=pencil&quantity=50" />
ide
因为buy.php脚本使用$_REQUEST而不是$_POST,这样每个只要是登陆在store.example.org商店上的用户就会经过请求该URL购买50支铅笔。网站
跨站请求伪造攻击的存在是不推荐使用$_REQUEST的缘由之一。google
生成表单tokencode
<?php session_start(); $token = md5(uniqid(rand(), TRUE)); $_SESSION['token'] = $token; $_SESSION['token_time'] = time(); ?>
提交表单的时候,token也之前提价到服务器。
<form action="buy.php" method="POST"> <input type="hidden" name="token" value="<?php echo $token; ?>" /> <p> Item: <select name="item"> <option name="pen">pen</option> <option name="pencil">pencil</option> </select><br /> Quantity: <input type="text" name="quantity" /><br /> <input type="submit" value="Buy" /> </p> </form>
一个跨站请求伪造攻击就必须包括一个合法的验证码以彻底模仿表单提交。因为验证码的保存在用户的session中的,攻击者必须对每一个受害者使用不一样的验证码。这样就有效的限制了对一个用户的任何攻击,它要求攻击者获取另一个用户的合法验证码。使用你本身的验证码来伪造另一个用户的请求是无效的。
该验证码能够简单地经过一个条件表达式来进行检查:
<?php if (isset($_SESSION['token']) && $_POST['token'] == $_SESSION['token']) { /* Valid Token */ } ?>
你还能对验证码加上一个有效时间限制,如5分钟,而且让token只能使用一次:
<?php $token_age = time() - $_SESSION['token_time']; $token = $_SESSION['token']; unset($_SESSION['token']); if ($token_age <= 300) { /* Less than five minutes has passed. */ } ?>
经过在你的表单中包括验证码,你事实上已经消除了跨站请求伪造攻击的风险。能够在任何须要执行操做的任何表单中使用这个流程。
你也可让token只能使用一次,在每次请求被请求后token经过后销毁这个token。能够更安全,同时也能够防止表单重复提交。使用cookei验证
若是咱们不考虑用户的Cookies很容易因为网站中存在XSS漏洞而被偷窃(咱们已经知道这样的事情并很多见)这一事实,这是一个很好的应对对CSRF的解决方案。若是咱们为用户的每个表单请求中都加入随机的Cookies,那么这种方法会变得更加安全,可是这并非十分合适
<?php // Hash the cookie $hash = md5($_COOKIE['cookie']); ?> <form method="POST" action="resolve.php"> <input type="text" name="first_name"> <input type="text" name="last_name"> <input type="hidden" name="check" value="<?=$hash;?>"> <input type="submit" name="submit" value="Submit"> </form> <?php // Check if the "check" var exists if(isset($_POST['check'])) { $hash = md5($_COOKIE['cookie']); // Check if the values coincide if($_POST['check'] == $hash) { do_something(); } else { echo "Malicious Request!"$$ } } else { echo "Malicious Request!"$$ } ?>
这个方案的思路是:每次的用户提交都须要用户在表单中填写一个图片上的随机字符串,厄....这个方案能够彻底解决CSRF,但我的以为在易用性方面彷佛不是太好