使用安全和会话,这是否足够安全?

时间:2013-09-15 23:58:38

标签: php session sessionid

访问此页面时只有1个用户名和1个密码,因此决定将其存储在PHP本身中,因为它可能比将其存储在数据库中更安全。但是,我试图抓住会话并希望:

  1. 它不会以任何方式危及安全。
  2. 当其他人尝试登录并失败时,它不会停止会话(对于已登录的用户)脚本的运行。例如,我不希望它删除登录用户的会话。可能是一个愚蠢的问题,但我想我还是会问。
  3. 我的index.php文件,在php中看起来像这样:

    session_start();
    
    if (!isset($_SESSION['Admin']))
    {
        if (isset($_POST['username'], $_POST['password']) && $_POST['username'] == 'someUsername' && $_POST['password'] == 'someVeryStrongPassword')
        {
            $_SESSION['Admin'] = true;
            session_write_close();
        }
        else {
                // You don't have access, go back to login page.
            session_destroy();
            header("location:login.php");
            exit();
        }
    }
    
    // This will now be used for any subsequent, same page requests, such as:  `index.php?action={something}`, etc. but will always use `index.php` as the main page.
    
    // Is it now safe to continue on with code assuming that the user is logged in at this point?  Should there be anything else to consider adding?  Possibly into the $_SESSION[] array?
    

    我的login.php文件只是HTML,看起来像这样:

    <!DOCTYPE html>
    <html>
    <head>
    <title>Administration</title>
    </head>
    <body>
    <form name="login" method="POST" action="index.php">
        <label for="user">Username: <input id="user" type="text" name="username" /></label><br />
        <label for="pass">Password: <input id="pass" type="password" name="password" /></label><br />
        <p><input type="submit" value="Login" /></p>
    </form>
    </body>
    </html>
    

    同样,我计划将$sess_id变量附加到index.php文件中提交的所有表单,并针对session_id()进行检查。这足够安全吗?一直在关注session_regenerate_idsession_id。人们报告说,session_regenerate_id在多个用户登录时会导致问题(旧会话ID与新会话ID)。在我的情况下(因为我没有将任何数据存储到数据库中),根本使用session_regenerate_id是明智的吗?

    感谢M Miller

    更新了代码

2 个答案:

答案 0 :(得分:1)

首先,我最初得知这个错误。我一直认为PHP会话本质上是独特而安全的。但是会话只是在浏览器会话结束时终止的cookie。 PHP会话比一般的cookie更加智能化,但它们具有大多数相同的漏洞和缺陷。简单的曲奇是不安全的。

首先,您应该设置session.use_only_cookies。通常,获取HTTP请求比从不知情的受害者获取cookie更容易。历史记录更容易阅读,人们经常清除cookie而不清除历史记录。它也显示在你的怪物显示器上,所以你的网址也可能是http://example.com/admin/index.php?username=admin&password=MyPaSsWoRd!123

您有两种可能的操作方法:如果您使用session_regenerate_id(true),则需要实现多个同时登录的系统 - 或者您可以假设如果有人从其他设备登录,则其他人都是访问将终止。

我更喜欢不活动超时,因为只要浏览器处于打开状态,会话就会持续 - 而且谁知道会有多长时间?

你只需要这个逻辑:

登录时:

<?php
$_SESSION['Admin'] = true;
$_SESSION['timeout'] = time()+3600; // +1 hour
?>

在随后的管理页面上:

<?php
if (!isset($_SESSION['timeout']) || $_SESSION['timeout'] < time()) {
   // destroy the session
   // redirect to login
   exit;
}
?>

(如果您正在开发UI,可能需要在超时接近时添加警告,以便用户不会丢失其信息。)

不要担心将所有内容都放在index.php上,因为这些都不重要。

不要依赖客户端的操作系统,浏览器或IP地址。这些是不可靠的,可能会发生变化,并且很容易被欺骗。虽然IP地址不能伪造(从技术上讲,不得用于任何用途),但您的IP地址可能会在会话期间发生变化,您可能会将自己锁定。

说实话,如果您要同时从不同设备进行多次登录,我将避免重新生成会话ID。如果您是唯一的用户,那么请使用它,因为它确实增加了一层安全性。方案是,如果获得会话ID,黑客只有一个短暂的机会窗口,可以在您(即用户)重新生成会话之前使用该会话。

查尔斯·米勒写了一篇关于持久身份验证的精彩文章,这是我要指向的地方,因为这就是我学习如何进行身份验证的方式:http://fishbowl.pastiche.org/2004/01/19/persistent_login_cookie_best_practice/(忽略底部的Barry Jaspan链接,它实际上并不是更安全,而且不必要地更加复杂。)session_regenerate_id会使实现这个系统变得非常简单 - 如果你只有一个用户,这将非常简单。实际上,您可以存储会话ID的历史记录,并且假设在应用程序的可预见的未来不会重复使用会话ID(并且极不可能),您可以简单地说,如果有人试图使用以前使用过且现在无效的会话ID,您可以假设他们是黑客并采取相应行动。

这是一种实现的方法(为简单起见,不使用数据库):

<?php
$sessions = explode(PHP_EOL, file_get_contents('sessions.log'));
   // Get the history of all past sessions
if (in_array(session_id(), $sessions) {
   // The current session ID is a session that has already been discarded
   // Hijack alert!
   mail('youremail@example.com', 'HIJACK ALERT!', 'Somebody tried to use the session '.session_id().'! The bastard\'s IP was '.$_SERVER['REMOTE_ADDR'], 'From: php@server');
   session_destroy();
   echo 'Nice try, jerk! The admin has been notified....';
   exit;
}

if (isset($_SESSION['Admin']) && $_SESSION['Admin']) {
   // Logged in!
   file_put_contents('sessions.log', PHP_EOL.session_id(), FILE_APPEND);
      // Add the current session ID to a file containing a history of session IDs
   session_regenerate_id(true);
      // Regenerate the session and delete the old one
}
?>

(未经测试。)当然,这是一个相当原始的例子,但它可能就是你所需要的。

正如我在评论中提到的那样,最佳解决方案是HTTP身份验证,因此如果它是一个选项,请使用它。

我们谈到的最后一件事:哈希密码。如果有人可以访问您的文件服务器并因此访问您的源代码,那么您就会遇到麻烦,无论您的应用程序是否受到损害。但是,如果您在其他地方使用相同的密码,只能在源代码中存储它的哈希,以便您可以限制损坏。然后,如果您的密码与您的银行帐户密码相同,那么至少黑客只会看到

if (hash('whirlpool', $_POST['password'].$salt) == '9923afaec3a86f865bb231a588f453f84e8151a2deb4109aebc6de4284be5bebcff4fab82a7e51d920237340a043736e9d13bab196006dcca0fe65314d68eab9')

(在我看来,PS Whirlpool是最好的哈希。我最喜欢的方法是将密码分成两半并将盐粘在中间。然后,即使两者都已知并且黑客有超级哈希桌子,他还是搞砸了。例如$half = floor(strlen($password)/2); $hash = hash('whirlpool', substr($password, 0, $half).$salt.substr($password, $half));

答案 1 :(得分:0)

如果您只使用会话,则会话总是有可能被劫持。会话很好但你需要更多的保护才能让它更难进入。例如你可以...

1)检查客户端的IP地址是否在会话期间发生变化(这会使会话劫持屁股感到痛苦)

2)使用一些cookie来识别客户端