【问题标题】:Working with Security and Sessions, is this secure enough?使用安全和会话,这是否足够安全?
【发布时间】:2013-09-20 01:17:34
【问题描述】:

只有 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更新代码

【问题讨论】:

  • 您应该存储密码的哈希值。
  • 多个用户共享一个登录始终是 BAD BAD BAD。您如何确定哪个用户进行了更改?如何仅删除其中一个用户的访问权限?
  • @Fluffeh - 好的,谢谢,没问题,在这种情况下只有 1 个用户可以访问!谢谢
  • 请注意,您调用了两次session_start(),并且您应该在header('Location: login.php'); 之后调用exit;(我认为浏览器可以拒绝标题...我疯了吗? )。
  • @SolomonClosson,他们需要访问您的 Web 服务器才能读取 PHP 源代码。但我确实确认了我之前所说的,肯定添加exit,因为浏览器可以拒绝位置重定向并加载任何 HTML/执行任何 PHP 跟随它。

标签: php session sessionid


【解决方案1】:

首先,我一开始就知道这是错误的。我一直认为 PHP 会话本质上是独一无二且安全的。但是会话只是在浏览器会话结束时终止的 cookie。 PHP 会话比一般的 cookie 更智能,但它们也有大部分相同的漏洞和缺陷。单纯的 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
}
?>

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

最好的解决方案是,正如我在 cmets 中提到的,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));)

【讨论】:

  • 哦,另外,Charles Miller 示例中的 sessions.log 会变得非常大非常快。最好使用 MySQL 表并定期清除旧会话,因为黑客不会使用 2 周前发送的 session_id,如果他这样做了,最坏的情况是他无法登录,但是你没有收到电子邮件。一个如此愚蠢的黑客并没有真正威胁到足以保证发送电子邮件的程度。
  • 考虑使用 1 小时超时方法。我还应该使用session.use_only_cookies吗?我现在真的不想允许超过 1 个用户同时登录,因为我可以看到允许更多用户会更加复杂......并且只是试图让事情变得简单和安全!
  • 是的,无论如何你都应该在你的配置中设置use_only_cookies。这是一个很好的做法。这是一种允许用户方便地禁用 cookie(没有理性用户会这样做)的选择,但代价是降低服务器上其他所有人的安全性。躲开它。顺便说一句,我知道要消化很多东西,所以我在 Pastebin 上放了一个脚本。未经测试,但至少它显示了流程:pastebin.com/2QSdwvLP
  • 哇,太好了,但我没有看到你在那个 pastebin 示例中的任何地方使用 ini_set('session.use_only_cookies', 1);,除非它不需要它......另外,你用什么来生成 @ 987654338@,我现在正在考虑在那个 pastebin 示例中使用您的方法......似乎比我的更好。另外,在您的示例中,您是否使用 ADMIN_EMAIL 作为用户名?
  • 这是一个完整的工作示例(我有很多需要重新安排和调试)。我将在我的下一个 Persistent Auth 站点中自己使用它的一个变体。 copy.com/qmI7nIEXAVtZlKbk
【解决方案2】:

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

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

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

【讨论】:

  • 嗯,就是这样 1. 这将始终调用 index.php?action=someaction 并且永远不会超出 index.php 调用,以及 2. 为了增加安全性,添加 $sess_id to form action urls that are submitting to index.php?action=something , does this mean that I don't need to worry about this since $_SESSION['Admin']` 在我的 php 代码的前几行中应该会自动为我处理这个问题,对吗??
  • 如果用户有动态IP地址或者同时使用多个设备,你就有问题了。
  • 好的,太好了,很高兴我在走session_id 路线之前问了这个问题!!
  • 是的,您不需要将会话 ID 附加到表单操作 url。实际上最好不要这样做,因为它很容易窃取会话 id,这显然不好。
  • 但是,现在我想一想……您总是可以从会话 ID、服务器时间、IP 地址中附加一个加盐哈希。或者甚至更好地将散列写入 cookie。你可以随心所欲,但最终你总是可以被破解的。因此,请记住您要保护的数据的重要性/敏感程度,并集成适当/匹配的保护。
猜你喜欢
  • 1970-01-01
  • 2013-02-03
  • 2015-06-06
  • 1970-01-01
  • 2016-08-12
  • 1970-01-01
  • 1970-01-01
  • 2014-08-16
  • 2021-04-14
相关资源
最近更新 更多