我是否过度回应了我的SESSIONS安全性?

Ene*_*oma 6 php mysql session

为了保护我的页面会话,我有以下几页.

我的问题是

  1. 我对此反应过度吗?
  2. 我应该将令牌放在login.php而不是loginForm.php吗?
  3. 当用户登录时,我将他的IP保存在数据库中.我应该在身份验证中使用它吗?

谢谢社区.

登录表单loginForm.php

$token = md5(uniqid(rand(),TRUE));
<input name="login" type="text" class="textfield" id="login" />
<input name="password" type="password" class="textfield" id="password" />
<input type="hidden" name="token" value="<?php echo $token; ?>" />
<input type="submit" name="Submit" value="Login" />
Run Code Online (Sandbox Code Playgroud)

当用户登录login.php时

$fingerprint = sha1('SECRET-SALT'.$_SERVER['HTTP_USER_AGENT'].$_SERVER['REMOTE_ADDR'].$_POST['token']);
    session_regenerate_id();
    $member = mysql_fetch_assoc($result);
$_SESSION['SESS_MEMBER_ID'] = $member['member_id'];
$_SESSION['SESS_TOKEN'] = $_POST['token'];
$_SESSION['SESS_FINGERPRINT'] = $fingerprint;
session_write_close();
    header("location: index.php");
    exit();
Run Code Online (Sandbox Code Playgroud)

在每个页面上验证auth.php

    session_start();
    $fingerprint = sha1('SECRET-SALT'.$_SERVER['HTTP_USER_AGENT'].$_SERVER['REMOTE_ADDR'].$_SESSION['SESS_TOKEN']);
    if( !isset($_SESSION['SESS_MEMBER_ID']) || (trim($_SESSION['SESS_MEMBER_ID']) == '')  || ($_SESSION['SESS_FINGERPRINT'] != $fingerprint) || !isset($_SESSION['SESS_TOKEN']) || (trim($_SESSION['SESS_TOKEN']) == '') ) {
        header("location: denied.php");
        exit();
    }
Run Code Online (Sandbox Code Playgroud)

irc*_*ell 4

回答您最关心的 3 个问题:

  1. 我对此反应过度吗?

    没有。损坏的会话管理在OWASP 十大漏洞列表中排名第三。您的实施存在一些问题,但总的来说这是一个好主意。

  2. 我应该将令牌放在login.php而不是loginForm.php中吗?

    有点儿。您应该将令牌生成直接放入会话中。然后,将其插入会话中的表单中。这样您就可以验证表单提交是否与请求表单的会话相同(可以防止某些攻击)。它基本上可以防止 CSRF 攻击。

  3. 当用户登录时,我将他的 IP 保存在数据库中。我应该在身份验证中使用它吗?

    不会。用户经常会从多台计算机登录。不存在真正可能的 IP->用户映射。IP->会话映射可能效果更好,但不要忘记,动态 IP 地址后面有相当数量的用户,因此即使对于会话来说,它也可能不可靠。

以下是对您的代码本身的一些评论:

  • 代币生成。 现在,您正在使用以下算法:

    $token = md5(uniqid(rand(),TRUE));
    
    Run Code Online (Sandbox Code Playgroud)

    我个人会将其更改为更加随机和安全的内容。例如:

    $token = md5(uniqid(mt_rand() . mt_rand(), true);
    
    Run Code Online (Sandbox Code Playgroud)

    或者,如果您安装了 mcrypt,我会这样做:

    $token = md5(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM));
    
    Run Code Online (Sandbox Code Playgroud)

    原因是这两个函数都具有更多的熵(意味着它们将生成大量唯一值),并且攻击者更难以猜测它们。

  • 指纹。 现在,你正在做:

    $fingerprint = sha1(
        'SECRET-SALT' . 
        $_SERVER['HTTP_USER_AGENT'] . 
        $_SERVER['REMOTE_ADDR'] . 
        $_POST['token']
    );
    
    Run Code Online (Sandbox Code Playgroud)

    这有一些问题。首先,动态IP地址会错误地使会话无效。其次,没有真正的理由对这些数据进行哈希处理。将每个字段保留为单独的字段,然后单独验证它们。它可以帮助防止某种理论上的攻击,即具有不同远程 IP 的用户可以创建伪造的令牌和用户代理,从而产生相同的哈希值(因此能够“破解”指纹)。第三,您使用输入的令牌作为识别数据。这可能会导致会话固定式攻击。

    我的建议是将每条信息存储在其自己的会话变量中,并单独验证它们。此外,请使用您在上一个请求中生成的会话令牌,并且仅验证发布的令牌是否与您保存的令牌匹配。

  • 会话验证。那里相当不错。我建议将其移至单独的函数中,以便在需要更改算法时可以轻松修改。这样你就可以调用:

    require_once 'session.php';
    verifySession();
    
    Run Code Online (Sandbox Code Playgroud)

    在每个文件的顶部...

您所拥有的显然是程序性的,并且可以从一些设计和抽象中受益,但在大多数情况下它都非常好(撇开上述评论)。