0

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

  1. 它不会以任何方式损害安全性。
  2. 当其他人尝试登录并失败时,它不会停止会话(对于已登录的用户)脚本的运行。例如,我不希望它删除登录用户的会话。可能是一个愚蠢的问题,但我想我还是会问。

我的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

4

2 回答 2

1

首先,我一开始有点学错了。我一直认为 PHP 会话本质上是独一无二且安全的。但是会话只是在浏览器会话结束时终止的 cookie。PHP 会话比一般的 cookie 更智能地制作,但它们具有大多数相同的漏洞和缺陷。单纯的饼干是不安全的。

首先,你应该设置session.use_only_cookies. 通常,获取 HTTP 请求比从毫无戒心的受害者那里获取 cookie 更容易。历史更容易阅读,人们经常在不清除历史的情况下清除 cookie。它也会显示在你的显示器上,所以你最好将你的 URL 设为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,黑客只有很短的机会使用该会话,然后您(用户)重新生成该会话。

Charles Miller 写了一篇关于持久身份验证的精彩文章,这就是我要指出的地方,因为这是我学习如何进行身份验证的方式: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));

于 2013-09-16T00:56:13.397 回答
0

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

1)检查客户端的IP地址是否在会话期间发生变化(这使得会话劫持很麻烦)

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

于 2013-09-16T00:16:19.033 回答