【问题标题】:PHP - Session identifier - SecurityPHP - 会话标识符 - 安全性
【发布时间】:2017-10-09 11:11:22
【问题描述】:

我有一个关于使用全局 $_SESSION[] 变量的问题。

到目前为止,对于我的 Web 应用程序,每当用户登录时,都会返回与该用户名和该特定密码匹配的行。然后我得到user_hash 列并将user_hash 存储在$_SESSION['id'] 中。

我使用此会话来识别哪个用户已登录并根据此唯一哈希执行数据库查询。我在某处读到这样的“静态”标识符(静态标识符是 user_hash,因为它永远不会改变)是不安全的,我宁愿让 user_hash 动态更改。

所以我实现了一个系统,每次用户登录和/或导航到 Web 应用程序中的其他页面时,我都会生成一个新的哈希值,将其存储在数据库中,然后将其存储在全局 $_SESSION['id']多变的。我设法做到了这一点,但现在每次有人尝试从两台设备登录时,具有“旧”会话的设备无效,因为 user_hash 从新设备更改并使用旧会话注销用户。

我的问题是,这样做真的有任何意义吗?我正在为我的网络服务器使用 ssl (https),​​所以我认为会话劫持相对来说是不可能的?如果仅具有静态会话标识符存在安全漏洞,是否有更好的方法使其动态化,同时不注销其他用户?

【问题讨论】:

  • 使用 https 仍然可以进行会话劫持、跨站脚本或 sql 注入
  • @RaymondNijland 虽然会话劫持在使用 TLS 时通常需要用户浏览器中的恶意软件,而这确实不是网站可以轻松防范的事情。如果您通过 https 传输会话 ID,则不会受到中间人攻击,这是会话劫持的常见形式。
  • @Devon 我的意思是会话劫持,攻击者正在暴力破解 session_id 以找到用户正在使用的有效会话...。默认的 PHP 会话处理不是很安全
  • 这里是关于与 Laravel 的讨论的快速阅读:github.com/laravel/framework/issues/15252。简而言之,您可以执行应用程序逻辑来为重要的事情(删除某些内容、访问帐户详细信息等)要求密码,但 https 是防止劫持的最佳保护。
  • 请使用段落。像这样的文本块很难阅读。我编辑了。

标签: php security session ssl session-variables


【解决方案1】:

两个有用的链接

http://blog.teamtreehouse.com/how-to-create-bulletproof-sessions

https://paragonie.com/blog/2015/04/fast-track-safe-and-secure-php-sessions


我设法做到了,但现在每次有人尝试从两台设备登录时,具有“旧”会话的设备无效,因为 user_hash 从新设备更改并注销用户旧会话。

虽然这可能取决于您的安全要求,但我在上面发布的first link 表示:

将旧会话标记为已过时,并将其标记为在 10 秒 [或适合您需要的某个时间] 后过期。这样,任何排队的请求仍然可以访问过期的会话,但我们不必让它永远打开。

static function regenerateSession()
{
    // If this session is obsolete it means there already is a new id
    if(isset($_SESSION['OBSOLETE']) || $_SESSION['OBSOLETE'] == true)
        return;

    // Set current session to expire in 10,30,100 seconds etc.
    $_SESSION['OBSOLETE'] = true;
    $_SESSION['EXPIRES'] = time() + 10; //or 30 seconds or whatever.

    // Create new session without destroying the old one
    session_regenerate_id(false);

    // Grab current session ID and close both sessions to allow other scripts to use them
    $newSession = session_id();
    session_write_close();

    // Set session ID to the new one, and start it back up again
    session_id($newSession);
    session_start();

    // Now we unset the obsolete and expiration values for the session we want to keep
    unset($_SESSION['OBSOLETE']);
    unset($_SESSION['EXPIRES']);
}

所以我实现了一个系统,每次用户登录和/或导航到 Web 应用程序中的其他页面时,我都会生成一个新的哈希值,将其存储在数据库中,然后将其存储在全局$_SESSION['id'] 变量。

就个人而言,我怀疑它的效率极低,并且会导致您在这种不断的改造中产生大量的服务器负载开销。只是不需要。

如果您真的想重新设计会话,只需使用session_regenerate_id() 并将其设置为一个时间值(例如每 10 分钟一次),如本文顶部的outlined in the first link

唯一重要的是会话标识会话数组中的所有值浏览器或最终用户永远不会看到

所以;只要您的会话 id 是 LONG 随机值,它就会隐藏在明显的视线中。从second link above 获取更多关于如何确保 PHP 为您提供更多随机和更长命名会话 id 的详细信息。

php.ini:

session.save_handler = files
session.use_cookies = 1
session.cookie_secure = 1
session.use_only_cookies = 1
session.cookie_domain = "example.com"
session.cookie_httponly = 1
session.entropy_length = 32
session.entropy_file = /dev/urandom
session.hash_function = sha256
session.hash_bits_per_character = 5  

如果将会话存储在数据库中,请确保为会话 ID 设置足够长的列名,否则会话将由于会话名称被截断而永远无法连接。


其他一些因素

  • 请确保 PHP 将您的会话 cookie 设置为 encrypted。无论您的 TLS 连接的状态如何,这都必须手动完成。参见上面的session.cookie_secure=1

  • 1234563比较浏览器类型/客户端 IP 仍然与会话记录中的内容进行比较。这两种方法中的每一种都可能存在问题,例如移动连接上的少数人可能会在登录期间更改 IP,或者多个设备上的用户可能会在每个设备上使用不同的浏览器,但可以根据需要找到一种方法进行比较 (这在页面顶部的first link 中也有引用)
  • 如上所述,$_SESSION 数据永远不会存储在客户端计算机上,因此从数据库中散列值以存储在 $_SESSION 中很可能超出了您的安全需求。

  • (唯一的)最重要的一点是会话 ID 是安全的并且足够大,可以轻松容纳潜在的黑客使用虚假会话 ID 钓鱼,就像在我的世界中玩战舰一样

【讨论】:

  • 谢谢!很好的答案!
  • @tomSurge 很高兴听到它。哪些部分让您最了解?有什么你已经知道的吗?
猜你喜欢
  • 1970-01-01
  • 2015-01-17
  • 2020-04-16
  • 1970-01-01
  • 2012-04-27
  • 2012-04-12
  • 2012-07-22
相关资源
最近更新 更多