访问此页面时只有1个用户名和1个密码,因此决定将其存储在PHP本身中,因为它可能比将其存储在数据库中更安全。但是,我试图抓住会话并希望:
我的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_id和session_id。人们报告说,session_regenerate_id
在多个用户登录时会导致问题(旧会话ID与新会话ID)。在我的情况下(因为我没有将任何数据存储到数据库中),根本使用session_regenerate_id
是明智的吗?
感谢M Miller
答案 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来识别客户端