这篇文章介绍的内容是关于php表单防止重复提交(防csrf漏洞) ,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下
Token浅谈
Token,就是令牌,最大的特点就是随机性,不可预测。一般黑客或软件无法猜测出来。
那么,Token有什么作用?又是什么原理呢?
Token一般用在两个地方——防止表单重复提交、anti csrf攻击(跨站点请求伪造)。
两者在原理上都是通过session token来实现的。当客户端请求页面时,服务器会生成一个随机数Token,并且将Token放置到session当中,然后将Token发给客户端(一般通过构造hidden表单)。下次客户端提交请求时,Token会随着表单一起提交到服务器端。
然后,如果应用于“anti csrf攻击”,则服务器端会对Token值进行验证,判断是否和session中的Token值相等,若相等,则可以证明请求有效,不是伪造的。
不过,如果应用于“防止表单重复提交”,服务器端第一次验证相同过后,会将涩session中的Token值更新下,若用户重复提交,第二次的验证判断将失败,因为用户提交的表单中的Token没变,但服务器端session中Token已经改变了。
上面的session应用相对安全,但也叫繁琐,同时当多页面多请求时,必须采用多Token同时生成的方法,这样占用更多资源,执行效率会降低。因此,也可用COOKIE存储验证信息的方法来代替session Token。比如,应对“重复提交”时,当第一次提交后便把已经提交的信息写到COOKIE中,当第二次提交时,由于COOKIE已经有提交记录,因此第二次提交会失败。
不过,COOKIE存储有个致命弱点,如果COOKIE被劫持(xss攻击很容易得到用户COOKIE),那么又一次gameover。黑客将直接实现csrf攻击。
1.首先防范xss攻击
2.验证referrer
3.重要COOKIE设置https only ,比如token
4.使用签名,令牌
5.get只用于查询信息
6.表单提交用post
7.谨慎使用跨脚本注入
所以,安全和高效相对的。具体问题具体对待吧。
php表单加入Token防止重复提交
原理在于生成一个随机字符串放在session里,提交表单后来验证这个字符串,可以做到防止他人自己写form来欺骗提交,重复提交或者双击提交。
简单的用php实现的代码如下:
php/** PHP简单利用token防止表单重复提交* 此处理方法纯粹是为了给初学者参考*/session_start();function set_token() {$_SESSION['token'] = md5(microtime(true));}function valid_token() {$return = $_REQUEST['token'] === $_SESSION['token'] ? true : false;set_token();return $return;}//如果token为空则生成一个tokenif(!isset($_SESSION['token']) || $_SESSION['token']=='') {set_token();}if(isset($_POST['test'])){if(!valid_token()){echo "token error";}else{echo '成功提交,Value:'.$_POST['test'];}}?>$_SESSION['token']?>">
上面的比较简单一点的方法,下面的代码更加安全一点。
Token.php
php/** Created on 2013-3-25** To change the template for this generated file go to* Window - Preferences - PHPeclipse - PHP - Code Templates*/function getToken($len &#61; 32, $md5 &#61; true) {# Seed random number generator# Only needed for PHP versions prior to 4.2mt_srand((double) microtime() * 1000000);# Array of characters, adjust as desired$chars &#61; array (&#39;Q&#39;,&#39;&#64;&#39;,&#39;8&#39;,&#39;y&#39;,&#39;%&#39;,&#39;^&#39;,&#39;5&#39;,&#39;Z&#39;,&#39;(&#39;,&#39;G&#39;,&#39;_&#39;,&#39;O&#39;,&#39;&#96;&#39;,&#39;S&#39;,&#39;-&#39;,&#39;N&#39;,&#39;<&#39;,&#39;D&#39;,&#39;{&#39;,&#39;}&#39;,&#39;[&#39;,&#39;]&#39;,&#39;h&#39;,&#39;;&#39;,&#39;W&#39;,&#39;.&#39;,&#39;/&#39;,&#39;|&#39;,&#39;:&#39;,&#39;1&#39;,&#39;E&#39;,&#39;L&#39;,&#39;4&#39;,&#39;&&#39;,&#39;6&#39;,&#39;7&#39;,&#39;#&#39;,&#39;9&#39;,&#39;a&#39;,&#39;A&#39;,&#39;b&#39;,&#39;B&#39;,&#39;~&#39;,&#39;C&#39;,&#39;d&#39;,&#39;>&#39;,&#39;e&#39;,&#39;2&#39;,&#39;f&#39;,&#39;P&#39;,&#39;g&#39;,&#39;)&#39;,&#39;?&#39;,&#39;H&#39;,&#39;i&#39;,&#39;X&#39;,&#39;U&#39;,&#39;J&#39;,&#39;k&#39;,&#39;r&#39;,&#39;l&#39;,&#39;3&#39;,&#39;t&#39;,&#39;M&#39;,&#39;n&#39;,&#39;&#61;&#39;,&#39;o&#39;,&#39;&#43;&#39;,&#39;p&#39;,&#39;F&#39;,&#39;q&#39;,&#39;!&#39;,&#39;K&#39;,&#39;R&#39;,&#39;s&#39;,&#39;c&#39;,&#39;m&#39;,&#39;T&#39;,&#39;v&#39;,&#39;j&#39;,&#39;u&#39;,&#39;V&#39;,&#39;w&#39;,&#39;,&#39;,&#39;x&#39;,&#39;I&#39;,&#39;$&#39;,&#39;Y&#39;,&#39;z&#39;,&#39;*&#39;);# Array indice friendly number of chars;$numChars &#61; count($chars) - 1;$token &#61; &#39;&#39;;# Create random token at the specified lengthfor ($i &#61; 0; $i <$len; $i&#43;&#43;)$token .&#61; $chars[mt_rand(0, $numChars)];# Should token be run through md5?if ($md5) {# Number of 32 char chunks$chunks &#61; ceil(strlen($token) / 32);$md5token &#61; &#39;&#39;;# Run each chunk through md5for ($i &#61; 1; $i <&#61; $chunks; $i&#43;&#43;)$md5token .&#61; md5(substr($token, $i * 32 - 32, 32));# Trim the token$token &#61; substr($md5token, 0, $len);}return $token;}?>
form.php
phpinclude_once("token.php");$token &#61; getToken();session_start();$_SESSION[&#39;token&#39;] &#61; $token;?>$token?>" />
action.php
phpsession_start();if($_POST[&#39;token&#39;] &#61;&#61; $_SESSION[&#39;token&#39;]){unset($_SESSION[&#39;token&#39;]);echo "这是一个正常的提交请求";}else{echo "这是一个非法的提交请求";}?>