最近保护我的网站我能够最好地对抗XSS我现在正在防范CSRF,观看并阅读了一些关于我创建以下代码的文章。
我想知道我的实现在数据库中使用字符串来帮助安全性是否正确。我应该采取哪些不同的做法?我应该检查双方的数据库吗?
代码:
if(!isset($_SESSION['register_token'])){
$keytype = 'register';
$getregisterkey = mysql_query("SELECT key FROM tokenkeys WHERE type='".$keytype."' ") or die(mysql_error());
while ($row = mysql_fetch_array($getregisterkey))
{
$registerkey = mysql_real_escape_string($row['key']);
};
$_SESSION['register_token']=sha1(uniqid(rand(), TRUE).$registerkey);
$_SESSION['register_token_time']=time();
}
<input type="hidden" name="token" value="<?php echo $_SESSION['register_token'];?>" />
if($_POST['register_token']==$_SESSION['register_token']){
$register_token_age=time()-$_SESSION['register_token_time'];
if($register_token_age=>300){
//process form
} else{
//valid token but expired
}
} else{
die('Access Forbidden')
}
答案 0 :(得分:1)
XSRF令牌仅与发送页面的频道一样安全。仅在此表单上使用https
和https
,并仅将其提交到https
终结点。否则,MITM可以在表单提供时或提交时从表单中获取XSRF令牌。
while ($row = mysql_fetch_array($getregisterkey))
{
$registerkey = mysql_real_escape_string($row['key']);
};
在零行时永远不会执行,如果你以后做$getregisterkey
时没有得到多少熵
$_SESSION['register_token']=sha1(uniqid(rand(), TRUE).$registerkey);
所以如果返回零行,我会确保你的实现失败 - 快。也许更改为if ($row = mysql_fetch_array(...)) { ... } else { /* abort */ }
,因为您没有从额外的行中获益。
rand()
必须是真正随机的或cryptographically strong PRNG。
我不熟悉PHP的标准库,但[维基百科]认为rand()
不具有加密功能。 wikipedia说
有建议在PHP中添加强大的随机数生成。
Strong cryptography in PHP建议使用openssl_random_pseudo_bytes()
请勿使用rand()或mt_rand()
要在PHP中生成加密强大的随机数,您必须使用OpenSSL库的函数
openssl_random_pseudo_bytes()
。
如果您使用弱随机性,则攻击者可以观察您生成的数字(通过请求表单的多个版本并解析隐藏的输入)并使用它来确定下一个数字可能是什么并伪造CSRF令牌。 / p>
如果攻击者修改了'register_token_time'
会话属性,那么他们可以避免您的XSRF检查。
例如,如果您有一个页面
$_SESSION[$_POST['x']] = $_POST['y'];
然后攻击者可以POST
x=register_token&y=pwnd
替换会话中存储的register_token,然后发送带
的帖子token=pwnd
并绕过您的XSRF保护。