在 PHP 中安全地创建和销毁登录会话

2022-08-30 23:18:14

这是我在网站上控制身份验证的代码。我不确定我的逻辑是否正确。如果用户名和密码正确,则会发生以下情况:

if(session_start())
{
        session_regenerate_id(true);//without this the session ID will always be the same
        $_SESSION['loggedInUser'] = $uName;
        echo 'You are now logged in';
}
else echo 'Right password/username but session failed to start';

后续页面检查以查看用户是否通过以下方式登录

session_start();
if(isset($_SESSION['loggedInUser'])
{
 //rest of page
}
else echo 'you must log in';

注销时,我有

session_start();//if I don't have this the next line produces an error
session_unset();//destroys session variables
session_destroy();//ends session

我红色没有在注销时调用session_start(),但如果我没有它,我会收到消息。我该如何解决这个问题?Trying to destroy uninitialized session

是否建议基于 IP 地址和用户代理创建指纹?我红了,这很糟糕,因为如果多台计算机在计算机实验室中,它们可以共享相同的IP地址,并且所有流量都通过代理,并且如果它是动态的,则同一台计算机可以更改其IP地址。另一方面,这种情况多久发生一次?为了防止所有会话劫持,可能值得使用几个阻止的有效用途。

即使您可以推荐信誉良好的文章,我也应该阅读以了解此主题,那就太好了,谢谢。

5/6 个答案的投票数少于 0 :(下台选民可以发表评论,以便我知道该注意什么吗?


答案 1

首先,您应该阅读Mozilla WebAppSec安全编码指南 - 会话管理和OWASP A3-broken Authentication and Session Management。您可以配置 PHP 的会话处理程序以满足这些要求。

您应该防止的第一个缺陷是A9-传输层保护不足。简而言之,您不希望有人使用Firesheep之类的工具劫持会话。可以通过强制浏览器仅通过 https 发送会话 ID 来防止此攻击:

session.cookie_secure=1

您可以通过设置 httponly 标志来防止攻击者使用 XSS 获取会话 ID:

session.cookie_httponly=1

始终希望使用 Cookie 来存储您的会话 ID。如果可以使用 GET 或 POST 变量传递会话 ID,则攻击者可以使用会话固定攻击来劫持会话。考虑此攻击的另一种方法是,您不希望攻击者为其他用户创建会话:

session.use_cookies=1
session.use_only_cookies=1

接下来,您要确保从 CSPRNG 获得至少 128 位熵。在*nix系统下,您可以使用:/dev/urandom

session.entropy_file="/dev/urandom"
session.entropy_length=16

会话处理程序不是全部。您仍然需要担心跨站点请求伪造攻击(也称为CSRF或“会话骑行”)和跨站点脚本(XSS)。XSS可以用来击败CSRF保护(即使有http_only cookie!攻击者还可以使用点击劫持来执行未经授权的操作。

设置这些配置选项后,只需调用 。至于在用户注销时销毁会话调用,就是这么简单!session_start()session_destroy()


答案 2

为了安全地销毁会话,我将使用以下代码:

session_start();
// Unset all session values
$_SESSION = array();
// get session parameters 
$params = session_get_cookie_params();
// Delete the actual cookie.
setcookie(session_name(), '', time() - 42000, $params["path"], $params["domain"], $params["secure"], $params["httponly"]);
// Destroy session
session_destroy();

为了销毁会话,您需要先启动它,因为您已经发现,如果您不包含session_start();

session_regenerate_id();函数为用户生成新的会话 ID。如果与 true (session_regenerate_id(true);) 一起使用然后,当旧会话 ID 生成新会话 ID 时,将从服务器中删除该 ID。在每个页面上生成新会话ID的原因是,由于用户不断更改会话ID,它使会话劫持更难执行(几乎不可能?)。

(查看session_regenerate_id()上的 PHP.net 手册);)

在对用户进行身份验证时,您应该始终检查诸如IP地址或浏览器之类的东西,这些是发送到服务器的请求中的常量内容,在会话的生命周期内不会更改,如果它们这样做,那么您知道发生了一些狡猾的事情。我总是创建两个会话变量,一个存储用户ID,以便我可以查询数据库中的数据,另一个将用户密码,IP地址和浏览器字符串全部存储在一个哈希(sha512)中。

$user_id = $_SESSION['user_id'];
$login_string = $_SESSION['login_string'];

// Query Database and get hashed password

$login_check = hash('sha512', $password.$ip_address.$user_browser);

if($login_check == $login_string) {
     // Logged In!!!!
     return true;
} else {
     // Not logged in
     return false;
}

即使密码存储在会话中,密码也是安全的。这是因为密码被散列(在本例中为两次),并且由于会话数据未存储在用户计算机上(如 Cookie),因此存储在会话文件中。

我写了一篇关于 wikihow.com 关于安全登录和身份验证的文章,可以在这里找到。


推荐