【问题标题】:Secure cookies in PHP sessionsPHP 会话中的安全 cookie
【发布时间】:2010-10-11 11:48:47
【问题描述】:

我开发了一个 PHP 会话类并使用几个示例对其进行了测试(请参阅下面的源代码)。似乎没问题。现在我想让这个会话以某种方式“安全”。我找到了一些用于加密 cookie 的示例代码(在 Courioso 的书 Expert PHP and MySQL 中)。这是这段代码sn-p。

加密 cookie 的代码

$cookieData = serialize($user);

$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
srand();
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$encryptedData = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $secret, 
            $cookieData, MCRYPT_MODE_CBC, $iv);
setcookie('user', base64_encode).':'.$iv);

以及用于解密 cookie 的类似代码

我的第一个问题是:我可以信任这段代码吗? IE。真的安全吗? (我尝试了那本书的一些其他代码示例,发现它们相当有问题)。

我不完全理解如何将加密 cookie 的代码嵌入到我的会话类中(上面的代码 - 或任何其他 cookie 加密代码)。我应该替换由 PHP (PHPSESSID) 自动生成的 cookie,还是应该生成一个新的 cookie 并加密这个自定义 cookie? (我猜第二个是真的,但我想确定一下)。

如何通过加密 cookie 进行保护?我想象以下攻击: (1) 如果攻击者不知何故拿到了他手中的 cookie,他只是用相同的 cookie 回复。好的。他没有密码,但他有加密的密码。稍后我只检查加密密码是否正常。因此,如果攻击者拥有 cookie:游戏结束 - 无论 cookie 是否包含密码或“仅”加密密码。正确的? (2) 好的,这个问题可以使用像 SSL 这样的加密传输来解决。但是我想如果我使用 SLL,那么传输无论如何都会被加密。我不需要使用加密功能再次输入密码。对吗?

这是我已经拥有的会话类的代码。

谢谢

<?php

class SessionClass {

    private static $_instance;
    public static function getInstance() 
    {
        if (!(self::$_instance instanceof self))
        {
            self::$_instance = new self();
        }
        return self::$_instance;
    } // getInstance


    public function __construct()
    {
        session_set_save_handler(
            array($this, "open"), array($this, "close"),
            array($this, "read"), array($this, "write"),
            array($this, "destroy"), array($this, "gc")
        );

        $createTable = "CREATE TABLE IF NOT EXISTS `session`( ".
                            "`sessionID` VARCHAR(128), ".
                            "`data` MEDIUMBLOB, ".
                            "`timestamp` INT, ".
                            "`ip` VARCHAR(15), ".
                            "PRIMARY KEY (`sessionID` ), ".
                            "KEY (`timestamp`, `sessionID`))";

        mysql_query($createTable);
    } // construct


    public function __destruct() {
        session_write_close();
    }

    public function open ($path, $id) {
        // do nothing
        return (true);
    }

    public function close() {
        // do nothing
        return (true);
    }

    public function read($id) 
    {
        $escapedID = mysql_escape_string($id);
        $query = sprintf("SELECT * FROM session WHERE sessionID = '%s'", $escapedID);
        $res = mysql_query($query);

        if ((!$res) || (!mysql_num_rows($res))) {
            $timestamp = time();
            $query = sprintf("INSERT INTO session (sessionID, timestamp) VALUES ('%s', %s)", $escapedID, $timestamp);
            mysql_query($query);
            return '';
        } elseif (($row = mysql_fetch_assoc($res))) {
            $query = "UPDATE session SET timestamp = ";
            $query .= time();
            $query .= sprintf (" WHERE sessionID = '%s'", $escapedID);
            mysql_query($query);
            return $row['data'];
        } // elseif

        return "";
    } // read


    public function write($id, $data)
    {
        $query = "REPLACE INTO session (sessionID, data, ip, timestamp) ";
        $query .= sprintf("VALUES ('%s', '%s', '%s', %s)", 
            mysql_escape_string($id), mysql_escape_string($data),
            $_SERVER['REMOTE_ADDR'], time());
        mysql_query($query);
        return (true);
    } // write


    public function destroy($id)
    {
        $escapedID = mysql_escape_string($id);
        $query = sprintf("DELETE FROM session WHERE sessionID = %s", $escapedID);
        $res = mysql_query($query);
        return (mysql_affected_rows($res) == 1);
    } // destroy


    public function gc($lifetime)
    {
        $query = "DELETE FROM session WHERE ";
        $query = sprintf("%s - timestamp > %s", time(), $lifetime);
        mysql_query($query);
        return (true);
    } // gc

} // SessionClass

【问题讨论】:

  • 您将sessionID存储在数据库中,这可以通过sql注入获得并用于登录,从而破坏了密码哈希的目的。
  • 如果 IP 地址位于负载均衡器后面,则它们在会话期间也可以更改。比如他们在学校或大型企业网络中。

标签: php security session cookies


【解决方案1】:

使用会话的原因是 不是将敏感数据存储在客户端,而是将其保存在服务器端。与这些数据的唯一联系是会话 ID,它有望随着每次身份验证和授权更改而定期更改。

如果您现在想在客户端存储该数据(无论以何种形式或表示形式),您将执行与会话的用途相反的操作。所以不要这样做,将敏感数据保存在服务器端。

【讨论】:

    【解决方案2】:

    如果我可以偏离你原来的问题。您应该不将密码存储在 cookie 中。 cookie 存储在客户端。不管加密是什么,更安全的选择是将您的用户身份验证详细信息保存在会话中,并简单地将令牌存储在客户端 cookie 上,该 cookie 将调用相应的会话。

    【讨论】:

    • 同意他应该把密码放在会话中,但这并不总是一个“更安全的选择”。例如,在某些共享主机设置中,会话信息对机器上的所有用户都是可读的。
    猜你喜欢
    • 2011-04-08
    • 1970-01-01
    • 2012-04-12
    • 1970-01-01
    • 2011-06-11
    • 2011-12-03
    • 2016-04-08
    • 2014-08-09
    • 2023-03-12
    相关资源
    最近更新 更多