开发者

Secure cookies in PHP sessions

开发者 https://www.devze.com 2023-01-19 17:48 出处:网络
I have developed a PHP session class and tested it using a few examples (see source code below). It appears to be okay. Now I would like to make this session somehow \"secure\". I found some sample co

I have developed a PHP session class and tested it using a few examples (see source code below). It appears to be okay. Now I would like to make this session somehow "secure". I found some sample code which is meant to encrypt a cookie (in Courioso's book Expert PHP and MySQL). Here is this code snippet.

Code for encrypted 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);

and a similar code for decrypting the cookie

My first question is: can I trust this code. I.e. is it really secure? (I tried some other code samples of that book and found them rather buggy).

I do not fully understand how the code for encrypting a cookie could be embedded into my session class (either the code above - or any other cookie encryption code). Should I replace the cookie which is automatically generated by PHP (PHPSESSID) or should generate a new cookie and encrypt this custom cookie? (My guess is the second is true, but I would like to be sure).

How is the protection via encrypted cookies meant to work? I imagine the following attack: (1) if the attacker get somehow the cookie in his hand he just replies with the same cookie. Okay. he does not have the password but he has the encrypted password. Later I check only if the encrypted password is okay. So if the attacker has th开发者_如何学JAVAe cookie: game over - no matter if the cookie contains the password or "only" the encrypted password. Correct? (2) Okay this problem can be solved using a cyphered transmission like SSL. But then I think if I use SLL than the transmission is anyway cyphered. I don't need to cypher the password a second time using the encryption function. Correct?

Here is the code for the session class I have already.

Thanks

<?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


The reason for using sessions is not to store sensitive data on the client side but to keep it on the server side. And the only connection to this data is the session ID that is hopefully changed periodically and with each authentication and change of authorization.

If you now want to store that data on the client side (no matter in what form or representation), you would do the opposite of what sessions are intended to be used for. So don’t do it and keep your sensitive data on the server side.


If I may digress from your original question. You should not be storing passwords in a cookie. A cookie is stored on the client side. Not matter what the encryption, a much more secure option would be to save your user authentication details in a session and simply store a token on the client side cookie which will call on the respective session.

0

精彩评论

暂无评论...
验证码 换一张
取 消