如何在PHP中实现增强的会话处理

6
我正在使用PHP中的会话,并在单个域上有不同的应用程序。问题是,cookie是特定于域的,因此会话ID将发送到单个域上的任何页面。(我不知道是否有一种使cookie工作方式不同的方法)。因此,在此域上的每个页面上都可以看到会话变量。
我正在尝试实现自定义会话管理器以克服这种行为,但我不确定我的想法是否正确。
我想完全避免PHP会话系统,并创建一个全局对象,它将存储会话数据,并在脚本结束时将其保存到数据库中。
1. 在首次访问时,我将生成唯一的session_id并创建一个cookie。 2. 在脚本结束时,使用session_id、会话开始时间戳和最后访问时间戳以及来自$_SERVER的数据(例如REMOTE_ADDR、REMOTE_PORT、HTTP_USER_AGENT)保存会话数据。 3. 在每次访问时,检查数据库中的从客户端发送的session_id cookie,检查IP、端口和用户代理(用于安全),并将数据读入会话变量(如果没有过期)。 4. 如果session_id已过期,则从数据库中删除。
该会话变量将被实现为单例模式(我知道会与此类产生紧密耦合,但我不知道是否有更好的解决方案)。
我正在尝试获得以下好处:
- 另一个服务器上的另一个脚本中不可见的会话变量 - 自定义会话过期管理 - 查看打开的会话的方法(类似于在线用户列表)
我不确定是否忽略了此解决方案的任何缺点。是否有更好的方法?
谢谢!

我看到在这种环境下部署应用程序将会有另一种安全威胁,我想要做的是最好的隔离,并且默认的会话处理似乎过于危险,不适合这样的使用。

因此我的问题是,如果您发现我的设计中存在比默认会话管理更不安全、更不灵活的东西..

感谢您的回答,..


锁定IP地址和端口不是一个好主意。因为通常情况下,两者都可以在请求之间发生变化。 - Gumbo
我不知道端口方面的情况,但我在某本PHP安全书中读到过,不应该允许来自不同IP的请求,因为这是一种常见的攻击方式,可以窃取会话ID,而IP限制可以避免使用被窃取的ID。我知道有些情况下你的IP可能会发生变化,但你知道这些情况是什么吗? - marianboda
一些互联网服务提供商会在每次请求时为用户分配一个新的IP地址。 - pinkgothic
是的,谢谢你,但我认为可以更安全地为具有动态 IP 的用户设置例外,并且对于具有固定 IP 的用户禁止 IP 切换会更好。嗯,谢谢,这需要进行正确的调整 :) - marianboda
6个回答

2

是的,我忽略了这个 :) 谢谢你。但是现在我想起来了,从安全角度考虑,如果您将已修改以在其他目录中工作的 cookie 发送到该服务器上的另一个应用程序,则该应用程序将访问该会话数据。 - marianboda
每个应用程序将提供不同的session_id。因此,它们无法访问彼此的数据。但是,您可能仍然具有使用默认“ /”路径的一些旧会话数据,因此在所有应用程序都安装修复程序后,您需要清除浏览器上的cookie。 - Foo
确保在session_start()之前调用它。 - Foo
每个应用程序都会给您不同的sessId,但是如果您将一个sessId传递到另一个应用程序中(我的意思是故意编辑cookie),php将读取该会话的数据,并且不会关心哪个应用程序创建了该会话。这对我来说很危险,因为在我的工作场所,同事们将拥有对我的Web应用程序的用户访问权限,但没有访问代码和数据库的权限。但是他们可以访问同一Web服务器上的不同文件夹。我不希望他们从我的Web应用程序中获取sessId,将其用于他们的php脚本以访问和修改会话数据,并获得他们不应访问的应用程序部分的访问权限... 这是一个复杂的问题,我很抱歉 :) - marianboda

1

是的,我做了,但我认为这并没有解决我在跨域会话变量可见性方面的主要问题。 - marianboda

1

如果您不想与共享会话遇到问题,可以使用session_save_path函数设置一个路径,应用程序将在其中保存其会话文件。由于该路径不是服务器上其他应用程序使用的路径,因此您不会遇到会话共享问题。

只有一件事:确保您保存会话文件的路径无法从Web访问。例如:

/YourAppFolder
     /www (web accessible)
     / libs
     /config
     / session (where you put your session files)

1

以下是你可以了解的内容:

  • 设置会话ID的路径和域。如果域名是.mastergaurav.com,那么cookie将被发送回mastergaurav.com、www.mastergaurav.com、blogs.mastergaurav.com等
  • 也许,如果你确实需要遍历多个顶级域名(TLD domains),而不是使用会话ID作为Cookie,可以将其作为URL的一部分,以完全自定义的方式实现:
    abcd.php?<?php echo session_name(); ?>=<?php echo session_id(); ?>&domain=<your-domain>

我认为你没有理解我的问题。我不涉及多个域名/子域名,即使我是,我认为这也无法解决我的任何子问题。 - marianboda

0

我想完全避免使用PHP会话系统,创建一个全局对象来存储会话数据,并在脚本结束时将其保存到数据库。

如果你考虑序列化对象,我不建议这样做,因为它不是保持安全细节的好方法。

http://www.php.net/manual/en/function.session-set-save-handler.php#81761

看一下上面的例子,他提供了一个很好的解决方案。

在不同域之间保持状态。

  1. 首先生成一个唯一标识符。
  2. 您可以创建一个cookie,在每个页面访问时读取该cookie。每次访问页面时,浏览器会将cookie发送到服务器。
  3. 如果您想使用另一种方法而不是cookie,还可以将您的唯一标识符作为每个URL的一部分传递。

更新:

  1. 首先,您需要根据IP地址限制用户访问您的应用程序,以使其更安全,这可以通过crossdomain.xml来实现。

  2. 您需要研究会话加密,以便即使用户将其拆分,也无法使用它。数据应使用私钥加密,并使用公钥解密。握手基于公钥。


连接应该在请求之间打开,并且只有在每次访问时发送查询。PHP会话默认使用文件,但也可以切换到数据库。在这种情况下,它与内置的数据库会话处理相同,而对于文件,我认为这是Web服务器的负担。据我所知,数据库更好地优化了这种数据访问。此外,两种方式都需要定期清理。是否有任何方法可以避免这种情况? - marianboda
数据库可以进行良好的优化。为了避免这种情况,您需要像我之前说的那样去获取cookie,其中您的cookie是从浏览器发送到服务器的。当用户从一个域跳转到另一个域时,获取cookie数据,将其传递到新域,最后再使用cookie数据重新发布。 - Thalaivar
我觉得我们在这里彼此不理解。我有1个域名,并在其上拥有更多的应用程序。其中一个应用程序是我构建的,其他应用程序应尽可能地隔离开来。我在对Foo的回答中进行了更详细的解释。 - marianboda
我读完你对foo的评论后感到非常困惑...你能告诉我你需要什么吗?抱歉...我在阅读那条评论后感到混乱。 - Thalaivar
加密是一种非常好的工具,但是它用于不同类型的工作。它的主要目的是为了在不安全的媒介上传输数据。它被设计成不能被第三方阅读到。我知道你正在提议出于同样的原因使用它,但是会话数据根本不应该对第三方可见,所以我正在试图隐藏它而不是模糊它。问题还在于你的解决方案中仍然可能更改会话中的数据,尽管很难使这些数据有效,但如果没有必要,我不想处理它。 - marianboda
显示剩余4条评论

0
我不确定是否忽略了这种解决方案的任何缺点。有更好的方法吗?
这很复杂,而且不会起作用,例如远程端口将在请求之间更改,远程地址可能会更改。
至少有两个非常明显的解决方案,而无需重新发明会话处理的方式:
1)在每个应用程序中使用不同的会话cookie名称-请参见session_name() 2)将每个应用程序放在不同的子目录中(例如http://example.com/app1/http://example.com/app2/,...),并在cookie上设置路径-请参见session_set_cookie_params或使用不同的ini设置session.cookie_path

检查IP地址和端口并不是必要的功能,因此它不会成为我的设计失败的原因。我可以使用它来分析潜在的攻击,我可以限制选定的用户仅使用某个IP地址范围,我可以根据需要使用这些信息,也可以完全不使用。 你的解决方案可以解决那些cookie的问题,但是即使你劫持了从app1发送到app2的cookie,我也不希望会话变量在其他应用程序中可见。也许克服这个问题并不难,但它不会给我带来其他优势,比如更好的过期管理。 - marianboda
方法1确实会在整个应用程序中暴露会话ID。而方法2则不会。您如何使会话数据过期与您如何将用户与会话协调无关 - 您提出的会话过期方案有什么优于默认方法的地方吗?(我看不出任何区别,除了维护自己的代码增加了风险)。 - symcbean
我并没有说它会暴露会话ID。我试图解释一下我的问题更新中的攻击场景。会话过期 - 我已经有一个要求,即使某些用户的会话在很短的时间内过期。它必须是灵活的,因此来自公司IP范围的连接不需要像来自外部的连接那样快速过期。可以使其对于某些用户来说从某些IP完全不过期。让我们不要质疑这样做的安全性方面,但总的来说,拥有这样的灵活性可能非常有用。 - marianboda

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