【问题标题】:I want to figure out how cookies/ session variables interact to validate a user session我想弄清楚 cookie/会话变量如何交互以验证用户会话
【发布时间】:2015-03-30 17:16:20
【问题描述】:

---我一直在尝试使用 cookie/会话 ID,但在理解这些概念时有些困难。 我正在开发一个 Debian 发行版。使用 Burp 捕获/更改请求/响应。我知道的如下。

一个。 Cookie 存储在客户端计算机数据库的 /root/.mozilla/firefox/pya18ecc.default/cookies.sqlite 中。在 moz_cookies 表中。我正在使用 sqlite3 访问数据库。

b.会话变量存储在服务器上的 /var/lib/PHP5 中。

服务器上的PHP代码如下

<?php
require_once 'login.php';

$connection = new mysqli($db_hostname,$db_username,$db_password,$db_database);
if($connection->connect_error) die ($connect->connect_error);

if (isset($_SERVER['PHP_AUTH_USER']) &&
   isset($_SERVER['PHP_AUTH_PW']))
    {
        $username = mysql_entities_fix($connection,$_SERVER['PHP_AUTH_USER']);
        $password = mysql_entities_fix($connection,$_SERVER['PHP_AUTH_PW']);

        $query = "SELECT * FROM user WHERE username = '$username'";

        $result = $connection->query($query);

        if(!$result) die ($connection->error);
        elseif ($result->num_rows) 
        {
            $row = $result->fetch_array(MYSQLI_NUM);    
            $result->close();
            $salt1="!@#$";
            $salt2="$#@!";
            $token = hash('ripemd128',"$salt1$password$salt2"); 

            if($token == $row[3])
                {
                    session_start();
                    $_SESSION['username'] = $username;
                    $_SESSION['password'] = $password;
                    $_SESSION['forename'] = $row[0];
                    $_SESSION['surname'] = $row[1];
                        echo "$row[0] $row[1] : Hi '$row[0]' you are logged
                            in as '$row[2]'";
                    die("<p><a href = continue.php> CLICK HERE TO CONTINUE</a></p>");
                }
            else    {die("Invalid Username/ Password Combination");}            
        }
        else
            {
                die("Invalid Username/ Password Combination");
            }
    }
else
    {
            header('WWW-Authenticate: Basic realm="Restricted Section"');
                header('HTTP/1.0 401 Unauthorized');
                die("Please enter your username and password to Login");
    }
    $connection->close();
function mysql_entities_fix($connection,$var)
    {
        return htmlentities(mysql_entities_string($connection,$var));
    }
function mysql_entities_string($connection,$var)
    {
        if (get_magic_quotes_gpc()) $var = stripslahes($var);
        return $connection->real_escape_string($var);

    }
?>
  1. 当我发送请求 (1) 时,它看起来像这样。

请求(1)

 GET /ses3.php HTTP/1.1
 Host: 127.0.0.1
User-Agent: Mozilla/5.0 (X11; Linux i686;      rv:31.0) Gecko/20100101 Firefox/31.0 Iceweasel/31.5.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
  1. response(1) 是一个登录页面(基本 HTTP 身份验证)

响应(1)

HTTP/1.0 401 Unauthorized
Date: Sat, 28 Mar 2015 07:27:44 GMT
Server: Apache/2.2.22 (Debian)
X-Powered-By: PHP/5.4.36-0+deb7u3
WWW-Authenticate: Basic realm="Restricted Section"
Vary: Accept-Encoding
Content-Length: 48
Connection: close
Content-Type: text/html

Please enter your username and password to Login

----直到这里没有交换会话ID或cookie。 (如果我错了,提示我?)

  1. 我回复了用户名和密码,请求(2)是

请求(2)

GET /ses3.php HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (X11; Linux i686; rv:31.0) Gecko/20100101 Firefox/31.0     Iceweasel/31.5.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Authorization: Basic YnNtaXRoOm15c2VjcmV0

---- 在转发上述请求时,我观察到即使在转发响应(2)之前,我已经在 /var/lib/PHP5 中收到了会话 ID:cl5mi7tbhdnobpv8kkau7thjo6。那是因为服务器 已经创建了相同的内容并准备在响应中转发它 (2)

  1. 响应 (2) 是

响应(2)

HTTP/1.1 200 OK
Date: Sat, 28 Mar 2015 07:36:13 GMT
Server: Apache/2.2.22 (Debian)
X-Powered-By: PHP/5.4.36-0+deb7u3
Set-Cookie: PHPSESSID=cl5mi7tbhdnobpv8kkau7thjo6; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-    revalidate, post-check=0, pre-check=0
Pragma: no-cache
Vary: Accept-Encoding
Content-Length: 117
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html

Bill Smith : Hi 'Bill' you are logged
                             in as 'bsmith'<p><a href = continue.php> CLICK HERE TO CONTINUE</a></p>

----现在在检查 SELECT * FROM moz_cookies 时,我没有看到任何 cookie 保存在客户端 m/c 上。那么他们在哪里得救呢? (这是我的第一个问题)

  1. 接下来,我从服务器中删除了会话变量“cl5mi7tbhdnobpv8kkau7thjo6”,并再次点击了 客户端浏览器上的刷新按钮。请求(3)/响应(3)如下

请求(3)

GET /ses3.php HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (X11; Linux i686; rv:31.0) Gecko/20100101 Firefox/31.0 Iceweasel/31.5.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Cookie: PHPSESSID=cl5mi7tbhdnobpv8kkau7thjo6
Authorization: Basic YnNtaXRoOm15c2VjcmV0
Connection: keep-alive
Cache-Control: max-age=0

响应(3)

HTTP/1.1 200 OK
Date: Sat, 28 Mar 2015 07:50:01 GMT
Server: Apache/2.2.22 (Debian)
X-Powered-By: PHP/5.4.36-0+deb7u3
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Vary: Accept-Encoding
Content-Length: 117
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html

Bill Smith : Hi 'Bill' you are logged
                            in as 'bsmith'<p><a href = continue.php> CLICK   HERE TO CONTINUE</a></p>

-----现在服务器再次在 /var/lib/PHP5 下设置了相同的会话变量。服务器不应该识别会话变量吗?此外,如果由于保存的 Cookie 而发生这种情况,那么为什么我无法在 moz_cookies 表下看到它们.....请解释一下?(这是我的第二个问题)

【问题讨论】:

    标签: authentication php cookies session-management secure-coding


    【解决方案1】:

    需要考虑的一些事项:

    1. Cookie 可以存储在磁盘或内存中。它们的存储方式取决于浏览器设置(例如 Firefox 中的隐私浏览模式)和服务器设置(参见 PHP docs on session handling)。

    2. 可以使用 Keep-Alive 标头缓存 HTTP 连接。

    看起来您已设置为将服务器上的会话 ID 存储在文件中,但浏览器 cookie 存储在内存中而不是文件中,这就是为什么您看到的是 PHP 文件而不是 Firefox cookie文件。

    至于为什么即使您删除了文件,服务器仍会识别会话 ID,看起来发生的事情是 PHP 知道会话已通过身份验证,这意味着它必须缓存在服务器的 RAM 中。 (PHP 专家可能能够填写会话机制的细节)。

    在收到请求 3 后,PHP 会查找 session id 文件,当它没有看到它时,它会再次写入该文件,因为它知道 session 是有效的。这是预期的行为,因为如果您想删除会话,作为 PHP 程序员,您应该在 PHP 中执行此操作,而不是在幕后删除会话 id 文件。

    您会注意到客户端在请求 3 中发送了会话 id。客户端将在每个请求中发送会话 id cookie,但在此会话期间服务器不应再次使用 Set-Cookie 指令进行响应。浏览器现在拥有会话 id cookie,并且可以在每个请求中发送它,因此不需要进一步的身份验证。

    这种策略的弱点是它可能会留下会话劫持的可能性。如果攻击者可以从您的浏览器获取会话 id cookie,他们可以使用您的凭据对服务器执行命令。

    根据许多因素,获取会话 ID 对攻击者来说可能是一项简单的任务,也可能不是。例如,如果受害者的计算机受到攻击者控制的病毒或其他恶意软件的破坏,那么攻击者可能会在此时获取受害者的计算机并可以做任何他们想做的事情,包括获取会话 ID。其他攻击使用跨站点脚本 (XSS) 攻击来诱骗受害者的浏览器泄露会话 ID。

    针对 XSS 和会话劫持有特定的防御措施,同样,这个主题相当复杂,值得详细研究。例如,更安全的会话可能会使用随每次响应而更改的一次性令牌,尽管使用异步 HTTP 调用可能会使该策略变得复杂。

    【讨论】:

    • 我同意您将会话 ID 存储在内存中的观点,因此 PHP 已经知道有效会话。因为即使删除了服务器上的物理会话变量文件,会话仍在继续。
    【解决方案2】:

    到目前为止,还没有会话 ID 或 cookie 的交换。 (如果我错了,提示我?)

    不,这是正确的。直到这里,session_start 还没有被调用,所以没有会话 cookie 可以交换。

    现在服务器再次在 /var/lib/PHP5 下设置了相同的会话变量。服务器不应该识别会话变量吗?

    它可能应该,但它不是。我认为正在发生的事情:当客户端发送会话 id 时,服务器很乐意使用它,即使它还不知道。这可以(理论上)用于session fixation,这就是为什么建议每次会话中的某些内容发生更改时重新生成 id(实际上,session.use_trans_sid 默认设置为0,这使得会话固定更少的问题)。

    我觉得奇怪的是数据仍然存在(我无法复制这种行为)。我的猜测是您实际上是在重新提交表单?

    另外,如果发生这种情况是因为保存了 Cookie,那么为什么我无法在 moz_cookies 表下看到它们

    我的猜测是 cookie 仍然在浏览器内存中。您是否尝试过相同的操作,但通过浏览器界面删除了 cookie?

    杂项

    我知道这只是一个测试脚本,但仍然:

    • 建议使用准备好的语句而不是简单的转义。
    • 不要在会话中存储明文密码)。
    • 不要回显未经处理的用户输入。
    • 哈希值应该是特定于用户的,而不是特定于站点的。
    • htmlentities 可防止 XSS,而不是 SQL 注入,因此应在回显数据时应用,而不是在将数据插入数据库时​​应用。

    【讨论】:

    • 为您的详细回答干杯。是的,我尝试删除浏览器历史记录/cookies。然后在重新提交请求/刷新页面时(如您所料),GET 变量/会话变量被清除。因此,再次提示基本身份验证页面,并在 /var/lib/PHP5 文件夹中弹出一个新的 Session id。
    猜你喜欢
    • 2020-07-05
    • 2015-12-20
    • 2011-06-09
    • 1970-01-01
    • 2014-02-21
    • 1970-01-01
    • 2019-10-28
    • 2014-09-03
    • 1970-01-01
    相关资源
    最近更新 更多