CSRF令牌类

3

有人能向我解释如何保护个人资料页面,以防止错误的用户编辑URL以查看其他用户资料页面。我使用一个令牌类来生成一个随机数以防止跨站点请求伪造。由于某种原因它不起作用了,有什么建议或其他方法可以做到这一点。

另外,我收到以下错误:在PhpProject22_CSRF\profile.php的第12行中未定义索引:令牌。

<?php 
session_start();
require_once 'Classes/Token.php';
$tk = new Token();

if(isset($_POST['username'],$_POST['product'],$_POST['token'])){
$username = $_POST['username'];
$product = $_POST['product'];
if(!empty($product) && !empty($username)){
    if(Token::check($_POST['token'])){
        echo $_POST['token'].'<br>';
        $tk->get('username');
        $_SESSION['user'] = $tk->name();
        echo 'Process Order';
    }
}
}
?>

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>CSRF Protection</title>
</head>
<body>
    <form action="" method="POST">
        <div class="product">
            <strong>Profile</strong>
            <div class='field'>
                Username: <input type='text' name='username'>
            </div>
            <input type='submit' value='Order'>
            <input type='hidden' name='product' value='1'>
            <input type='hidden' name='token' value='<?php echo Token::generate();?>'>
        </div>
    </form>
    <?php
    if(isset($_POST['username'])){
    ?>
    <p>Hello <a href = 'profile.php?user=<?php echo $tk->name();?>'><?php echo $tk-  >name();?></a>!</p>
    <?php
    }
    ?>
</body>
</html>

<?php
class Token{
private $_data;

public static function generate(){
    return $_SESSION['token'] = base64_encode(openssl_random_pseudo_bytes(32));
}

public static function check($token){
    if(isset($_SESSION['token']) && $token === $_SESSION['token']){      
        unset($_SESSION['token']);
        return true;
    }
    return false;
}

public function get($item){
    if(isset($_POST[$item])){
        $this->_data = $_POST[$item];
    }
}

public function name(){
return $this->_data;
}
}
?>

<?php
require_once 'Classes/Token.php';
session_start();
?>
<form action="" method="POST">
<input type='hidden' name='token' value='<?php echo Token::generate();?>'>
</form>

<?php
echo 'Hello '.$_SESSION['user'].'!<br>';
if(isset($_GET['user'])){
if(Token::check($_POST['token'])){
    echo $_GET['user'];
}
}
?> 

在你的令牌类函数中放置session_start() - echolocation
你还应该在每次提交时检查CSRF,这将指示一个非法用户。同时,对CSRF令牌进行哈希处理并将其与会话ID绑定(假设已正确生成)是一个更好的想法。通过绑定,我指的是hash("sha512", (session_id() + openssl_random_pseudo_bytes(32)));可以很好地实现。 - echolocation
为什么我应该在令牌类中放置session_start(),它已经在index.php中定义了@echolocation? - Karish Karish
2
可能是因为您没有检查 $_POST['token'] 是否已设置。 - echolocation
是否已提交POST请求? - echolocation
显示剩余4条评论
1个回答

3

检查帖子时需要执行以下步骤:

if($_POST){
    if(isset($_POST['token']) && Token::check($_POST['token']){
        code
    }else{
        error
    }
}

如果有人伪造了帖子,并没有包含token,那么您将会收到一个未定义的索引错误,因为$_POST['token']不存在,而您正在引用它。

谢谢,它可以工作,但我能否不使用提交按钮,仅使用<input type='hidden' name='token' value='<?php echo Token::generate();?>'>? - Karish Karish
好的,表单仍然需要提交,所以你可以通过JavaScript来完成吗? - echolocation

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接