如何在 PHP 中安全地实现“记住我”按钮(持久登录)

     2023-03-08     162

关键词:

【中文标题】如何在 PHP 中安全地实现“记住我”按钮(持久登录)【英文标题】:How to securely implement the "Remember me" button in PHP (persistent login) 【发布时间】:2018-02-18 00:30:42 【问题描述】:

首先是一些背景知识,我还在学习 PHP,我正在尝试构建一个 CMS(免责声明:仅供我自己使用)。

我还在测试一些东西,我已经成功创建了一个管理员登录系统。

所以,现在它是这样工作的:

用户登录,在验证和清理输入后,我检查用户是否存在,并使用 PHPs password_verify 将密码与存储在数据库中的哈希密码进行比较。

如果登录成功,我会将管理员重定向到 dashboard.php,并创建一个名为 adminId 的会话变量,并将用户 ID 存储在该变量中。

这是我的第一个问题:

攻击者可以更改$_SESSION['adminId'] 的值吗?例如,从 1 更改为 12,因此以不同的管理员身份登录?

无论如何,我已经阅读了this article,其中介绍了攻击者可以使用的多个漏洞。

所以,如果我没记错的话,我应该使用 cookie 进行持久登录,对吗?

好的,所以第一件事是永远不要将用户 ID 存储在 cookie 中并使用它来检查登录,因为攻击者可以很容易地更改它吗?

好的,所以我可以创建一个随机令牌(使用 random_bytes 然后转换为十六进制)并将其与数据库中 logins 表中的用户 ID 配对。强>

例如,我有这个:

token: 2413e99262bfa13d5bf349b7f4c665ae2e79e357,
userId: 2

因此,用户登录,创建令牌,并使用 userId 存储在数据库中。 假设用户关闭了浏览器。 然后他再次打开它,里面只有带有令牌的 cookie:2413e99262bfa13d5bf349b7f4c665ae2e79e357。如此自动地,它使用 userId: 2 登录用户,对吗?

如果他想以 userId: 10 的用户身份登录,他需要知道与该用户配对的随机令牌。

很好,但是有这个问题:时序泄漏。所以他们提出了一个使用两个东西的解决方案,一个选择器和一个验证器。看不懂的时候,文章是这样说的:

以下是我们提出的策略,用于在 Web 应用程序中处理“记住我”cookie,而不会将任何有用信息(甚至时间信息)泄露给攻击者,同时仍然快速高效(以防止拒绝服务攻击)。

我们提出的策略在一个关键方面偏离了上述简单的基于令牌的自动登录系统:我们存储selector:validator,而不是仅在 cookie 中存储随机的token

selector 是一个唯一 ID,便于数据库查找,同时防止不可避免的时间信息影响安全。 (这比简单地使用数据库id 字段更可取,它会泄露应用程序上的活动用户数。)

在数据库方面,validator 不是批发存储的;相反,validator 的 SHA-256 散列存储在数据库中,而明文存储(使用 selector)在用户的 cookie 中。有了这种故障保护措施,如果 auth_tokens 表以某种方式泄露,就可以防止立即进行广泛的用户模拟。

自动登录算法类似于:

    selectorvalidator 分开。 获取auth_tokens 中给定选择器的行。如果没有找到,则中止。 使用 SHA-256 对用户 cookie 提供的 validator 进行哈希处理。 使用 hash_equals() 将我们生成的 SHA-256 哈希与存储在数据库中的哈希进行比较。 如果第 4 步通过,请将当前会话与相应的用户 ID 相关联。

所以这就是我不明白的地方

1) selectorvalidator 应该包含什么? 2) 为什么这个系统是安全的以及它如何防止时序泄漏?

在此先感谢,很抱歉发了这么长的帖子,但我真的很想了解它是如何工作的以及如何实现它。

我知道我可以使用一些框架或库,但我想从头开始,通过反复试验学习!

【问题讨论】:

在我看来,考虑到这种情况,时间攻击不太可能发生。但是,您可能需要查看 JSON Web Tokens (JWT) 来解决您的问题。您只需将令牌存储在用户端,并且由于它是从您的服务器发出的(理想情况下具有到期日期/时间),因此您可以控制身份验证令牌的发出和维护。 那么,假设我不处理时序泄漏,而我采用令牌方法,我完全按照我在帖子中所说的去做,它安全吗? 假设您在合理的时间后使令牌过期(从而防止重放攻击),是的。 【参考方案1】:

攻击者可以更改$_SESSION['adminId'] 的值吗?例如,从 1 更改为 12,因此以不同的管理员身份登录?

没有。会话数据仅存储在服务器上。客户端只有标识会话的字符串。

我应该使用 cookie 进行持久登录,对吗?

如果您要进行持久登录,通常是这样做的。

所以第一件事是永远不要将用户 ID 存储在 cookie 中并使用它来检查登录,因为攻击者可以轻松更改它吗?

正确,您永远不想公开任何关键数据,例如用户 ID。

1) selectorvalidator 应该包含什么?

每个都是正确生成的随机字符串(例如使用openssl_random_pseudo_bytes)。 selector 必须是唯一的。

2) 为什么这个系统是安全的以及它如何防止时序泄漏?

与生成一个基本令牌并直接查找它相比,它增加了两个安全功能。

首先,如果您的数据库泄露给攻击者,他们将无法生成自己的记住我的 cookie 并模拟每个用户。 validator 仅作为散列值存储在数据库中。 cookie 必须包含未散列的值。反转一个好的哈希非常耗时。

其次,比较仅在服务器上生成的哈希可以避免定时攻击。如果攻击者发送各种记住我的 cookie 值来计时他们的查找,它不会暴露任何有用的信息,因为服务器上的比较是针对散列值而不是原始值。

一般来说,如果您的系统安全性如此重要,我建议您完全不要支持记住我功能。如果您确实想在重要站点上使用此功能,请使用已经过安全测试的库。

【讨论】:

您好,感谢您的回答。关于选择器,我只有一个问题。现在我正在使用它生成它:base64_encode(random_bytes(8)); 但这不是唯一的吗?如何在不检查数据库并检查它是否已经存在的情况下使其唯一? @nick 为了保证它是独一无二的,你必须检查数据库。 我不能使用时间戳并将其用作盐或类似的东西(例如将其附加到选择器的末尾)吗? @nick 是的。尽管从理论上讲,这使得它更可预测。但坦率地说,如果您的网站被小心攻击的几率非常高,那么您无论如何都不会使用记住我的 cookie。所以我个人认为使用时间戳+盐生成很好。

PHP登录系统:记住我(持久cookie)[重复]

...登录前添加一个“记住我”复选框选项。在用户浏览器中安全存储cookie的最佳方式是什么?例如,Facebook有“记住我”复选框,这样每次您进入facebook.com时,您就已经登录了。我当前的 查看详情

如何安全实现“记住我”功能

1.利用token原理:每次登录时为用户生成一个token并存放于cookie中,下次登录时,验证token是否正确并自动登录这样每次生成时失效时间不同,token也不同缺点:1.安全问题,当cookie被窃取(可以为cookie设置http-only,防范XSS、csrf等攻... 查看详情

“记住我” - 在 cookie 中保留啥? -PHP [重复]

...ESSION。现在,我想用cookie实现“记住我”的可能性。出于安全原因,我应该把coo 查看详情

Git http - 安全地记住凭据

】Githttp-安全地记住凭据【英文标题】:Githttp-securelyremembercredentials【发布时间】:2011-09-0517:25:31【问题描述】:当通过HTTP(S)连接到远程存储库时,有没有办法让git安全地记住我的凭据?我尝试了git-config中详述的core.askpass方法,... 查看详情

如何实施安全的“记住我”

】如何实施安全的“记住我”【英文标题】:Howtoimplementsecure"Rememberme"【发布时间】:2018-07-2508:45:20【问题描述】:我正试图弄清楚如何在我正在开发的应用程序中实现“记住我”。目前我的实现是这样的。用户登录并请... 查看详情

如何使用 php/jquery 实现持久页面?

】如何使用php/jquery实现持久页面?【英文标题】:Howtoimplementpersistentpageusingphp/jquery?【发布时间】:2011-12-0401:44:37【问题描述】:您在页面的不同区域加载了包含大量ajax内容的页面display.php。用户在页面内部单击,ajax内容的某... 查看详情

如何在登录页面中以 Angular 2 实现“记住我”

】如何在登录页面中以Angular2实现“记住我”【英文标题】:howtoimplement"rememberme"inangular2,inloginpage【发布时间】:2018-03-0100:24:15【问题描述】:我尝试在Angular2中实现记住我,例如使用documnent.cookie和ngx-cookie。但不工作。... 查看详情

如何在 PHP 中安全地返回文件数据

】如何在PHP中安全地返回文件数据【英文标题】:HowtoreturnfiledatasecurelyinPHP【发布时间】:2015-04-3019:03:25【问题描述】:底线问题:什么是正确的PHP,以便我可以在基于json的响应对象中包含二进制数据文件?我有一个正在与服务... 查看详情

如何在 PHP 中安全地存储包含敏感数据的 cookie?

】如何在PHP中安全地存储包含敏感数据的cookie?【英文标题】:HowtostorecookiescontainingsensitivedatasecurelyinPHP?【发布时间】:2012-08-0214:26:33【问题描述】:我希望我的用户在登录我的网站时能够“保持登录状态”。在这篇文章的最佳... 查看详情

如何在将文件包含在 PHP 中之前安全地评估文件的内容

】如何在将文件包含在PHP中之前安全地评估文件的内容【英文标题】:Howtosafelyevaluateafile\'scontentsbeforeincludingitinPHP【发布时间】:2021-10-0922:05:27【问题描述】:我正在使用返回数组的PHP文件作为一种配置方式。为了处理这些配置... 查看详情

PHP“记住我”安全漏洞?

】PHP“记住我”安全漏洞?【英文标题】:PHP"RememberMe"securityflaw?【发布时间】:2012-12-1708:12:17【问题描述】:我正在编写一个配备“记住我”的登录表单,到目前为止,我阅读的教程(部分是为了确保我做对了)都说要... 查看详情

如何在 C++ 中安全地实现可重用的暂存存储器?

】如何在C++中安全地实现可重用的暂存存储器?【英文标题】:HowtosafelyimplementreusablescratchmemoryinC++?【发布时间】:2021-10-1408:35:45【问题描述】:即使是纯函数也需要一些额外的临时内存来进行操作,这是很常见的。如果在编译... 查看详情

在 PHP 中使用“记住我”功能的正确方法

...2012-02-1300:12:09【问题描述】:短正在开发登录系统并尝试实现记住我的功能。最近,我对这个主题进行了研究,阅读了一堆文章、帖子、故事、小说、童话(这么称呼它们,因为其中一些甚至不包含一行代码,只是一堆单词)关... 查看详情

如何使用 PHP 安全地将 JSON 数据写入文件

】如何使用PHP安全地将JSON数据写入文件【英文标题】:HowtosafelywriteJSONdatatofileusingPHP【发布时间】:2011-09-0510:26:13【问题描述】:我有用于编辑图像的HTML表单。所有数据都存储在JSON中。当我更改当前图像时,我想通过PHP脚本将... 查看详情

在这个持久登录实现中,添加系列标识符有何帮助?

】在这个持久登录实现中,添加系列标识符有何帮助?【英文标题】:Howdoestheadditionofaseriesidentifierhelpinthispersistentloginimplementation?【发布时间】:2015-07-2311:33:45【问题描述】:原创“记住我”登录实现:http://fishbowl.pastiche.org/2004/... 查看详情

如何安全地实现“基于令牌的身份验证”以访问在 PHPFox 中开发的网站资源(即功能和数据)?

】如何安全地实现“基于令牌的身份验证”以访问在PHPFox中开发的网站资源(即功能和数据)?【英文标题】:Howtoimplement\'TokenBasedAuthentication\'securelyforaccessingthewebsite\'sresources(i.e.functionsanddata)thatisdevelopedinPHPFox?【发布时间】:20... 查看详情

如何安全地对要从 UI 中删除的按钮进行内存管理?

】如何安全地对要从UI中删除的按钮进行内存管理?【英文标题】:HowcanIsafelymemorymanageabuttonthatIwanttoremovefromtheUI?【发布时间】:2010-10-0618:41:22【问题描述】:我正在制作一个有点像iBooks的应用程序。屏幕上有一些东西,每个项... 查看详情

如何安全地停止 AVAudioPlayer

】如何安全地停止AVAudioPlayer【英文标题】:howtostopAVAudioPlayersecurely【发布时间】:2011-12-1119:11:54【问题描述】:我有一个带有两个按钮的AVAudioPlayer:播放和停止。播放时播放按钮隐藏,反之亦然。问题是当我尝试按下停止按钮... 查看详情