这是设置令牌CSRF的安全方法吗?

时间:2012-12-09 17:53:51

标签: php security

我想知道这是否是设置令牌的安全方式,除非实际存在令牌,我生成一个令牌,并在整个应用程序和那些表单中使用它。每个会话一个令牌?

if (!isset($_SESSION['token'])) {
    $data['token'] = uniqid(rand(), true);
    session_regenerate_id();
    $_SESSION['token'] = $data['token'];
}

是否有必要在提交的表单上清除令牌?或者只是坚持下去,即使我提交了一份表格?

6 个答案:

答案 0 :(得分:11)

如果您不知道这些链接,this应该可以帮助您了解某些情况,特别是this会告诉您DO和DONT。希望它有所帮助。

答案 1 :(得分:10)

我个人会为我想要显示的每个表单生成一个新标记。如果你这样做,只要会话保持活动状态,有人只需要一个会话cookie来读取你的令牌并使用它。

在我的应用程序中,我为每个表单显示生成一个令牌,如下所示:

<?php
$token = uniqid(rand(), true);
$_SESSION['csrf_tokens'][$token] = true;

<强> HTML

<form>
    <input type="hidden" name="token" value="<?php echo $token ?>" />
</form>

在表单验证时,我会检查这个令牌:

if (isset($_SESSION['csrf_tokens'][$token]) && $_SESSION['csrf_tokens'][$token] === true) {
    unset($_SESSION['csrf_tokens'][$token]);
    // additional code here
}

答案 2 :(得分:2)

除了使用per-session token我更希望per-form/url token获得额外的安全性,有些人可能会认为per-request token最安全,但会影响可用性。

我还认为最好将会话存储与令牌存储分开并使用Memcache之类的内容。当您需要使用多个应用程序服务器等速度时,这会更好。我也更喜欢它,因为我可以添加自定义expiration to the token而不必影响整个session

这是一个典型的例子

<强> HTML

<form method="POST" action="#">
    IP:<input type="text" name="IP" /> <input type="hidden" name="token"
        value="<?php echo Token::_instance()->generate(); ?>" /> <input
        type="Submit" value="Login" />
</form>

处理

$id = "id44499900";
Token::_instance()->initialise($id); // initialise with session ID , user ID or IP

try {

    Token::_instance()->authenticate();
    // Process your form
} catch ( TokenException $e ) {
    http_response_code(401); // send HTTP Error 401 Unauthorized
    die(sprintf("<h1>%s</h1><i>Thief Thief Thief</i>", $e->getMessage()));
}

使用的课程

class Token {
    private $db;
    private $id;
    private static $_instance;

    function __construct() {
        $this->db = new Memcache();
        $this->db->connect("localhost");
    }

    public static function _instance() {
        self::$_instance === null and self::$_instance = new Token();
        return self::$_instance;
    }

    public function initialise($id) {
        $this->id = $id;
    }

    public function authenticate(array $source = null, $key = "token") {
        $source = $source !== null ? $source : $_POST;

        if (empty($this->id)) {
            throw new TokenException("Token not Initialised");
        }

        if (! empty($source)) {
            if (! isset($source[$key]))
                throw new TokenException("Missing Token");
            if (! $this->get($this->id . $source[$key])) {
                throw new TokenException("Invalid Token");
            }
        }
    }

    public function get($key) {
        return $this->db->get($key);
    }

    public function remove($key) {
        return $this->db->delete($key);
    }

    public function generate($time = 120) {
        $key = hash("sha512", mt_rand(0, mt_getrandmax()));
        $this->db->set($this->id . $key, 1, 0, $time);
        return $key;
    }
}
class TokenException extends InvalidArgumentException {
}
  

注意:请注意,该示例可能会影响“后退”按钮或刷新,因为令牌会在120秒后自动删除,这可能会影响用户友好功能

答案 3 :(得分:2)

  

我想知道这是否是设置令牌的安全方式

这取决于您的网络应用程序需要多么安全。此行不具有加密安全性(正如在uniqid()和rand()的PHP文档中所警告的那样:

uniqid(rand(), true);

如果已知/确定了令牌生成的时间并且已知/确定了rand()种子,则攻击者可以确定/强制执行此操作。但是,出于您的目的,它可能会很好,因为它仍会阻止攻击者不知道令牌值的CSRF攻击。

  

每个会话一个令牌?

每个会话使用一个令牌可能适用于您的目的。但请注意:

  1. 如果会话长达n分钟,则攻击者有一个n分钟的窗口来尝试确定或获取您的令牌值并执行CSRF攻击。然而,当每个表单生成令牌时,或者当令牌被定期重新生成时,这种风险会降低,因为它们不够长寿。
  2. 如果攻击者确定/获取令牌,则每个会话使用一个令牌会公开您的所有应用程序的功能(使用该令牌)进行攻击。而每个表单使用一个令牌可以将攻击限制为单个表单。
  3.   

    是否有必要在提交的表单上清除令牌?或者只是留下来,即使我提交了一份表格?

    这取决于您的应用程序针对攻击者的目标值以及攻击导致您的中断程度。您现有的措施使得执行CSRF攻击变得困难,但如果它具有很高的价值并且您拥有非常坚定的攻击者,那么您可能希望通过以下方式降低CSRF的风险:

    1. 使用加密安全令牌来防止确定或暴力强制令牌值的风险。
    2. 定期重新生成令牌以减少令牌生命周期,如果确定或获得令牌,则减少攻击窗口。
    3. 在确定或获取令牌的情况下,为每个表单生成令牌以限制对单个表单的攻击。

答案 4 :(得分:1)

您可以参考以下网站,这可能会有一些想法。

1。)https://docs.djangoproject.com/en/dev/ref/contrib/csrf/

2。)http://blog.whitehatsec.com/tag/session-token/

感谢您的回复。

答案 5 :(得分:1)

我已经在另一个论坛上回答了类似的问题:here。希望这很有帮助。它解释了CSRF预防的基本过程,并链接到CSRF框架的一些代码。

如果您想要更高的安全性,请在每次会话的每次请求后更改令牌。如果您想要更好的可用性,请在每个会话中保留一个令牌。