如果我想保护我的网站和用户免受跨站点伪造(CSRF)攻击,我可以在每个页面上生成一个具有表单的唯一令牌$token = md5( time() * rand );
。令牌在隐藏的输入字段echo '<input type="hidden" name="token" value="'.$token.'">';
中提交,同时存储在会话变量$_SESSION['token'] = $token;
中。
我会检查是否在提交的任何表格if($_POST['token'] == $_SESSION['token'])
上并继续进行。
然而,有些用户可能会执行多任务。我正在发布的内容正是我现在正在做的事情。
在撰写我的帖子时,我打开了不同的窗口/标签,可能会研究信息或查看有关堆栈溢出的其他一些问题。堆栈溢出让我提交表单没有问题。
但是如果我在我的网站上这样做 - 这意味着在编写帖子/表单的同时浏览其他页面 - 每次我从我的网站上拉出不同的页面时,我的$token
都会重新生成。在我正在处理的表单上创建隐藏的input
令牌,并最终提交不正确的,因为它不再匹配$_SESSION['token']
变量,当我访问时已重新生成一个不同的页面...
任何好的想法如何防止这个问题,或者首先阻止CSRF的更好的解决方案?
我希望允许我的用户执行多项任务并希望受到CSRF保护......
答案 0 :(得分:4)
由于单个CSRF,我的状态存在同样的问题,除非他们提交最新的页面,否则会被替换,但是如果你使用数组w / session它应该解决你的问题。此外,您可能想要包含验证码,我建议使用Google的Recaptcha。
session_start();
function createToken(){
$token = sha1(uniqid(mt_rand(), true));
$_SESSION['Tokens']['Token'][] = $token;
$_SESSION['Tokens']['Time'][] = time() + (10 * 60); #10 min limit
#you can omit/change this if you want to not limit or extend time limit
return $token;
}
function checkToken($token){
clearTokens();
foreach($_SESSION['Tokens']['Token'] as $key => $value){
if($value === $token){
return true;
}
}
return false;
}
function clearTokens(){
foreach($_SESSION['Tokens']['Time'] as $key => $value){
if($value <= time()){
unset($_SESSION['Tokens']['Token'][$key], $_SESSION['Tokens']['Time'][$key]);
#remove last parameter if you aren't using token time limit
}
}
}
你的HTML:
<input type="hidden" name="token" value="<?php createToken(); ?>">
PHP令牌检查器
if(isset($_POST['token']) && checkToken($_POST['token'])){
#valid token
}else{
#create error message saying that they tried to repost data or session token expired
}
答案 1 :(得分:2)
浏览器应该在选项卡和窗口之间保持正确的会话ID,会话ID应该相同。 (危险假设应该通过浏览器进行测试以确定)
根据会话ID生成更多应该有效的令牌。
所以你可以检查一下这样的事情。
$tokenCorrect = false;
foreach($_SESSION['tokens'] as $token) {
if ($token !== $_POST['token'])
continue;
$tokenCorrect = true;
}
if ($tokenCorrect == false) {
die(); //
// Maybe log to database ?? but watch if possible Denial of Service because somebody can write your disk/ shared diskspace full with only making fast requests with a invalid CSRF token
}