在PHP中使用会话和cookie创建安全登录

15

我正在编写登录脚本,希望尽可能地使其安全。问题是,安全似乎是一个永远无法结束的战斗。因此,我正在寻找对我的想法的建议和改进。

我所拥有的只是基于会话的登录。每当会话信息发生变化时,将调用session_regenerate_id()以避免明显的劫持尝试。

当会话未设置时,我检查有效的登录cookie,在成功后更新会话。

我试图通过添加散列值和一些唯一用户信息(如用户名或ID)来保护cookie的安全性。这个哈希值由各种信息组成,包括用户名/ID,不可解密的密码哈希,IP地址的部分等。通过从cookie中提取用户名/ID,我可以从有效的用户信息生成新哈希并将其与cookie中的哈希进行比较。我的愿望是防止伪造的cookie和cookie劫持(除非他们也欺骗了IP地址)。

编辑假设登录本身将通过HTTPS / SSL完成,因此传输是(相对)安全的。

我走在正确的轨道上吗?还能做什么来保护我的登录?

感谢您的帮助!


http://phpseclib.sourceforge.net/ - Teson
这对于未来的安全相关主题非常有用(已经收藏了!),但我假设如果要保证传输安全,那么将使用SSL。我更多地寻找确保登录状态安全以防止通过不道德手段进行未经授权的进入的想法。 - steveo225
1
使用SSL怎么样?说到底,如果攻击者在同一网络上并进行嗅探,我认为这些都没有什么帮助,而且SSL也不是绝对安全的,但至少它不是明文传输。这是我的意见。 - Andreas Wong
我明白了。我已经说过两次了,我的问题不是关于从浏览器到网站的传输,因为这将使用SSL。我的问题是如何在事后保护登录状态,以防止劫持、虚假凭据等。 - steveo225
这正是我试图防止的。哈希块可以防止大多数伪造,因为攻击者必须猜测一个加密的密码,并且每次进行 cookie 登录时,都会在创建会话之前对已知信息进行验证。从那时起,会话就被使用了。那么,如何比我更安全地保护 cookie 和会话呢? - steveo225
显示剩余6条评论
5个回答

6
停止你正在做的事情。不要检查用户代理或IP地址。用户代理是由攻击者控制的变量,检查此值不会增加此系统的安全性。IP地址将因合法原因而更改,例如如果用户在负载均衡器或TOR后面。
会话ID必须始终是密码随机数。在PHP中,只需调用session_start(),然后开始使用$_SESSION超级全局变量即可。PHP会为您处理所有这些内容。如果要改进PHP的会话处理程序,请使用配置。启用use_only_cookiescookie_httponlycookie_secure。另外,如果您在*nix系统上,则将entropy_file设置为/dev/urandom是一个好主意,但如果您在Windows下,则会遇到麻烦。
例如,要验证用户:
//In a header file
session_start();
...
if(check_login($_POST['user_name'],$_POST['password'])){
   //Primary key of this user
   $_SESSION['user_id']=get_user_id($_POST['user_name']);
   $_SESSION['logged_id']=True;
}

并验证用户是否已登录:

//in a header file
session_start()
...
if(!$_SESSION['logged_id']){
   header("location: login.php");
   die();//The script will keep executing unless you die()
}

为了改进该系统,请阅读OWASP A9,并在整个会话期间使用HTTPS。同时阅读OWASP A5:CSRF,也称为“会话劫持”,以及OWASP A2:XSS,因为它们都可以用来危及会话。

这些都很好,而且大部分正是我正在做的。但是关于 cookie 呢?我使用它来在会话之间记住登录状态,这样用户就不必一天登录 5 次了。 - steveo225
@steveo225 session_start() 会为您创建一个 cookie。您可以通过配置 php 来更改过期时间。 - rook
是的,我明白这一点,但我不想设置一个持续几天甚至几周的过期时间。 - steveo225
@steveo225 平台需要一个过期时间,因为如果没有过期时间会存在漏洞,这被称为永久会话。请记住,这个值可以被暴力破解,并且没有速率限制器或日志记录。 - rook
这就是我的观点。我不想让会话持续那么长时间,所以我使用 cookie 来“刷新”会话,作为一种手段来保持用户登录的时间,只要我认为合适。因此,从我所知道的情况来看,我几乎做到了所有正确的事情来保护会话和维护登录详细信息,但是,我想制作一个“安全”的 cookie,它极难被复制、伪造、劫持等。 - steveo225
显示剩余5条评论

3

如果cookie不仅通过SSL传输,那就没有所谓的安全cookie可言。使用永久性的非会话cookie(如“记住我”)可以减轻一些问题,可以执行您正在执行的操作,但不能像您想要的那样。

您确实可以存储服务器变量,例如用户代理、IP地址等(甚至JavaScript变量),但它们只适用于验证持久cookie数据是否与客户端的新连接匹配。IP地址不是一个好主意,除非您知道客户端(例如您)每个页面加载时不会更改(类似AOL)。

现代Web浏览器和LastPass等第三方服务可以存储只需按下键(有时甚至不需要)即可将登录凭据发送到登录表单的登录凭据。永久性cookie仅适用于拒绝使用其他可用选项的人。最终,持久性的非会话cookie并不再真正是必需的。


2
好的,基本上,我可以做一些事情来混淆cookie,使其更难伪造、破解、复制等,但最终,如果用户选择“记住我”,如果连接不安全,确保安全性就是他们的责任,而我无能为力... - steveo225

1

我使用基于cookie的方法(使用setcookie函数),但是....

session_start();
...
if(check_login($_POST['user_name'],$_POST['password'])){
   //Primary key of this user
   $_SESSION['user_id']=get_user_id($_POST['user_name']);
   $_SESSION['logged_id']=True;
}

这些方法都是错的!!!

我使用基于cookie的攻击方式破解了我的网站。

  1. 我使用WebCruiser漏洞扫描器的cookie选项,以便在登录后获取我的cookie。
  2. 然后我更改了cookie上的一个简单值。
  3. 接着我点击保存cookie。
  4. 此时,我点击浏览器左侧面板上的查看,然后点击右侧,再点击刷新页面,这样我就可以不使用用户名和密码的登录页面而直接进入管理员页面。

因此,如果有人向您推送病毒以读取IE或Firefox的cookie历史记录,您会很高兴地发现您的管理员用户名和密码可以被他人使用。

那么如何解决这个问题呢?简单:将cookie与会话服务器或会话的cookie与会话服务器相结合,或将会话与文件会话相结合,或将cookie与文件会话相结合......虽然安全但速度慢 :((((


0

SESSION比cookie更安全,我的建议是为当前登录尝试创建一个唯一的ID,例如:

$id = uniqid();
$_SESSION['username'.$id] = "something ...";

一个带有索引用户ID的会话是否可以处理这个问题(通过自动创建的唯一会话ID)? - Snowburnt

0

我将所有的登录数据保存在用户会话中,这样它们都存储在服务器端。

我只会将像“自动登录”、“会话ID”之类的内容存储在客户端cookie中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接