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