我想弄清楚 cookie/会话变量如何交互以验证用户会话

I want to figure out how cookies/ session variables interact to validate a user session

---我一直在试验 cookies/session ids,但在理解这些概念时有点困难。 我正在开发 Debian 发行版。使用 Burp 来 capture/alter 请求/响应。我所知道的如下。

一个。 Cookie 存储在 /root/.mozilla/firefox/pya18ecc.default/cookies.sqlite 的客户端计算机数据库中。在moz_cookiestable。我正在使用 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. 响应(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

---- 在转发上述请求时,我观察到我在 /var/lib/PHP5 中收到了会话 ID:cl5mi7tbhdnobpv8kkau7thjo6,甚至在转发响应 (2) 之前。那是因为服务器 已经创建了相同的并准备在响应中转发它 (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,我没有看到任何保存在客户端 m/c 上的 cookie。那么他们在哪里得救呢? (这是我的第一个问题)

  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 table 下看到它们......请解释一下?(这是我的第二个问题)

需要考虑的几点:

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

  2. 可以使用 Keep-Alive header.

  3. 缓存 HTTP 连接

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

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

收到请求3后,PHP查找sessionid文件,没找到就重新写入文件,因为它知道session是有效的。这是预期的行为,因为如果你想删除 session,你作为一个 PHP 程序员应该在 PHP 中删除而不是删除后面的 session id 文件场景。

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

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

获取 session id 对于攻击者来说可能是也可能不是微不足道的任务,这取决于许多因素。例如,如果受害者的计算机受到攻击者控制的病毒或其他恶意软件的危害,攻击者可能会在此时伪造受害者的计算机并可以为所欲为,包括获取 session id。其他攻击使用 cross-site 脚本 (XSS) 攻击来诱骗受害者的浏览器泄露 session id。

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

Till here there has no exchange of session ids or cookies. (If I'm wrong, prompt me ?)

不,没错。直到这里,session_start 还没有被调用,所以没有会话 cookies 可以交换。

Now the Server has again got the same session variable set under the /var/lib/PHP5. Shouldn't the server not recognize the session variable ?

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

我觉得奇怪的是数据还在那里(我无法复制这种行为)。我猜您实际上是在重新提交表格?

Also if this is happening because of the saved Cookies, then why isn't I'm able to see them under moz_cookies table

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

其他

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

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