在PHP会话中保护cookie

时间:2010-10-11 11:48:48

标签: php security session cookies

我开发了一个PHP会话类,并使用一些示例对其进行了测试(参见下面的源代码)。看起来没问题。现在我想让这个会议以某种方式“安全”。我找到了一些用于加密cookie的示例代码(在Courioso的书籍Expert PHP和MySQL中)。这是代码片段。

加密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的类似代码

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

我不完全理解如何将加密cookie的代码嵌入到我的会话类中(上面的代码 - 或任何其他cookie加密代码)。我应该替换由PHP自动生成的cookie(PHPSESSID),还是应该生成一个新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

2 个答案:

答案 0 :(得分:2)

使用会话的原因是不会在客户端存储敏感数据,而是将其保留在服务器端。与此数据的唯一连接是会话ID,有希望定期更改,并且每次身份验证和授权更改。

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

答案 1 :(得分:1)

如果我可以偏离原来的问题。您应该将密码存储在cookie中。 Cookie存储在客户端。无论加密是什么,一个更安全的选择是在会话中保存您的用户身份验证详细信息,只需将令牌存储在客户端cookie上,该cookie将调用相应的会话。