PHP会话足够用户身份验证吗?

时间:2010-11-12 07:36:40

标签: php security session login

情景:

  • 用户登录后,会设置会话变量以确认其登录信息。
  • 在每个页面的顶部,登录会话变量已确认有效
  • 如果不是,他们就会被赶出去。
  • 不使用永久性Cookie,仅使用session

问题:

这本身就是一个足够强大的安全措施,还是应该

  • 设置两个会话变量以验证彼此和/或
  • 实施数据库/哈希验证
  • ...?

======

(顺便说一句,在我研究这个问题时,this wiki是一个很棒的读物。)

5 个答案:

答案 0 :(得分:6)

只需在会话中存储用户登录(或用户ID)即可。

为了防止会话固定/劫持你需要的只是实现简单的algorythm(伪代码):

if (!isset($_SESSION['hash']) {
    $_SESSION['hash'] = md5(!empty($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : 'no ua');
} else if ($_SESSION['hash'] != md5(!empty($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : 'no ua')) {
    session_regenerate_id();
    $_SESSION = array();
    $_SESSION['hash'] = md5(!empty($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : 'no ua');
}

您可以将哈希计算移动到某个函数中以防止重复,我刚刚展示了可能的保护草图。

这就是我在kohana会话课中实现这种保护的方式:

abstract class Session extends Kohana_Session
{
    public function read($id = null)
    {
        parent::read($id);

        $hash = $this->calculateHash();
        $sessionHash = $this->get('session_fixation');

        if (!$sessionHash) {
            $this->set('session_fixation', $hash);
        } elseif ($sessionHash != $hash) {
            $this->regenerate();
            $_SESSION = array();
            $this->set('session_fixation', $hash);
        }
    }

    private function calculateHash()
    {
        $ip = !empty($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1';
        $ua = !empty($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : 'no ua';
        $charset = !empty($_SERVER['HTTP_ACCEPT_CHARSET']) ? $_SERVER['HTTP_ACCEPT_CHARSET'] : 'no charset';
        $ip = substr($ip, 0, strrpos($ip, '.') - 1);
        return md5($ua . $ip . $charset);
    }
}

答案 1 :(得分:2)

不要尝试编写自己的会话方案,PHP会做得更好。

是的,您可以向$ _SESSION添加更多信息,以帮助防止会话劫持

例如,我通过将秘密短语或随机数据与用户代理和session_id()组合生成指纹,并将其全部哈希。要劫持会话,用户需要找出有效的session_id和指纹的哈希值。它看起来像这样。 This is a good read

$_SESSION['fingerprint'] = md5('somethingSecret' . $_SERVER['HTTP_USER_AGENT']. session_id());

然后你会像

那样验证会话
$check_print = md5('somethingSecret' . $_SERVER['HTTP_USER_AGENT']. session_id());

if($check_print != $_SESSION['fingerprint'] || $_SESSION['authenticated']){ 
    //invalid session
}

答案 2 :(得分:1)

截至11月15日,我收到的两个答案并未解决我的问题,即

“这个[单个会话变量]本身就是一个足够强大的安全措施吗?”

This question说是的,但似乎存在一些分歧。以下是各种结果的摘要:

1)自会话can be hijacked fairly easily以来,单个会话变量的安全性不够

2)由于可能发生这种情况,因此没有会​​话真正安全,但通过添加指纹可以使会话变得更安全。这确保了每次会话需要验证时都能进行独特,可重复的检查。 @zerkms建议使用User-Agent和其他一些哈希(请参阅他的代码)。

3)Salting the fingerprint几乎没用,因为它模糊了数据但在每台客户机上都被复制,因此失去了它的独特性。

4)数据库解决方案没用,因为它是客户端问题。

不是我一直在寻找的明确答案,但我想它必须做,因为缺乏更好的东西。

阅读有助于我进一步困惑:

Session hijacking and PHP

Is HTTPS the only defense against Session Hijacking in an open network?

答案 3 :(得分:1)

除了使用HTTPS之外,您无能为力。

您添加的Cookie数量或您散列的数据无关紧要;它都可以被嗅探并发送回服务器。

如果您要强制用户在其请求的整个生命周期内使用单个UA,这可能有所帮助:您不需要任何特殊的哈希业务,因为您将其哈希到$_SESSION用户和劫持者都无法直接访问,为什么还要麻烦呢?也可以在登录时存储$_SESSION["reportedUA"] = $_SERVER["HTTP_USER_AGENT"],然后在每个请求上检查reportedUA

一旦你意识到它正在发生,劫持也是微不足道的,因为你只需要在嗅探会话cookie时嗅探报告的UA,然后开始使用它。

下一步是什么? IP地址?会话劫持可能发生在NAT后面,在这种情况下你被搞砸了。您的用户可能正在使用拨号,在这种情况下他们搞砸了。

这个问题没有解决方案:没办法。没有办法。如果黑客可以看到你的会话cookie,那么他们就会搞砸你,因为没有额外的信息或挑战只与用户知道(即密码)的东西有关。

使会话安全的唯一方法是保护整个会话。

答案 4 :(得分:0)

  

这本身就是一个足够强大的安全措施,

     

设置两个会话变量以验证彼此和/或
  实现数据库/哈希验证

不,原因是:如果没有加密,那么您的有效用户可以发送到服务器进行身份验证的任何内容(会话ID,cookie,某些散列字符串,任何内容!)都可以被其他人嗅探。即使服务器使用md5散列,salt,双会话变量检查,id或其他任何内容来处理数据,并存储该信息,服务器在从其他来源再次接收欺骗数据时也很容易重现。

正如许多人所建议的那样,SSL是防止此类窃听的唯一方法。

我想到,如果服务器为每个请求生成一个新的会话ID,并允许浏览器只回复一次,理论上可能只有一个劫持者请求或在服务器和授权之前发布浏览器知道它。但是,仍然不能接受,因为一个人就足以造成严重的伤害。

嘿,这是怎么回事:

创建一次性GUID和随机盐并使用PHP使用共享密码对其进行加密 - 这将作为会话ID或cookie发送。

客户端收到cookie,使用javascript使用共享密码对其进行解密(有许多可用的enc / dec实用程序)

将当前cookie或会话ID设置为GUID。

这样可以确保没有人能够劫持会话,除非他们知道密码,而密码永远不会通过网络发送。

SSL似乎更容易,而且更安全。

编辑:好的,已经完成了 - 没关系; - )

相关问题