好的,有两个独立但相关的问题,每个问题的处理方式都不同。
会话固定
这是攻击者显式设置用户会话的会话标识符的地方。通常在 PHP 中,这是通过给他们一个像这样的 url 来完成的http://www.example.com/index...?session_name=sessionid
。一旦攻击者将 url 提供给客户端,攻击就与会话劫持攻击相同。
有几种方法可以防止会话固定(全部执行):
-
Set session.use_trans_sid = 0 https://www.php.net/manual/en/session.configuration.php#ini.session.use-trans-sid在你的php.ini
文件。这将告诉 PHP 不要在 URL 中包含标识符,并且不要读取 URL 中的标识符。
-
Set session.use_only_cookies = 1 https://www.php.net/manual/en/session.configuration.php#ini.session.use-only-cookies在你的php.ini
文件。这将告诉 PHP 永远不要使用带有会话标识符的 URL。
-
只要会话状态发生变化,就重新生成会话 ID。这意味着以下任何一项:
- 用户认证
- 在会话中存储敏感信息
- 更改有关会话的任何内容
- etc...
会话劫持
攻击者可以在这里获取会话标识符,并能够像该用户一样发送请求。这意味着,由于攻击者拥有标识符,因此他们与服务器上的有效用户几乎无法区分。
您无法直接阻止会话劫持。然而,您可以添加一些步骤来使其变得越来越难以使用。
-
使用强会话哈希标识符:session.hash_function https://www.php.net/manual/en/session.configuration.php#ini.session.hash-function in php.ini
。如果 PHP session.hash_function = 1对于 SHA1。如果 PHP >= 5.3,则将其设置为session.hash_function = sha256
or session.hash_function = sha512
.
-
发送强哈希:session.hash_bits_per_character https://www.php.net/manual/en/session.configuration.php#ini.session.hash-bits-per-character in php.ini
。将其设置为session.hash_bits_per_character = 5
。虽然这并不能解决任何问题harder为了破解,当攻击者试图猜测会话标识符时,它确实会产生影响。 ID 会更短,但使用更多字符。
-
设置附加熵session.entropy_file http://www.php.net/manual/en/session.configuration.php#ini.session.entropy-file and session.entropy_length http://www.php.net/manual/en/session.configuration.php#ini.session.entropy-length在你的php.ini
文件。将前者设置为session.entropy_file = /dev/urandom
后者是将从熵文件中读取的字节数,例如session.entropy_length = 256
.
-
更改默认 PHPSESSID 的会话名称。这是通过调用来完成的session_name() https://www.php.net/manual/en/function.session-name.php在调用之前使用您自己的标识符名称作为第一个参数session_start
.
-
如果你是really偏执的您也可以轮换会话名称,但请注意,如果您更改此名称(例如,如果您使其依赖于时间),则所有会话都将自动失效。但根据您的用例,这可能是一个选择......
-
经常轮换您的会话标识符。我不会对每个请求都这样做(除非你really需要那种安全级别),但间隔是随机的。您希望经常更改此设置,因为如果攻击者确实劫持了会话,您不希望他们能够使用它太长时间。
-
包括用户代理来自$_SERVER['HTTP_USER_AGENT'] http://php.net/manual/en/reserved.variables.server.php在会议中。基本上,当会话开始时,将其存储在类似的内容中$_SESSION['user_agent']
。然后,在每个后续请求中检查它是否匹配。请注意,这可能是伪造的,因此它不是 100% 可靠,但总比没有好。
-
包括用户的IP地址来自$_SERVER['REMOTE_ADDR'] http://php.net/manual/en/reserved.variables.server.php在会议中。基本上,当会话开始时,将其存储在类似的内容中$_SESSION['remote_ip']
。对于某些为其用户使用多个 IP 地址的 ISP(例如 AOL 过去的做法),这可能会出现问题。但如果你使用它,它会安全得多。攻击者伪造 IP 地址的唯一方法是在真实用户和您之间的某个时刻破坏网络。如果他们破坏了网络,他们的行为可能比劫持更糟糕(例如 MITM 攻击等)。
-
在会话中和浏览器端包含一个您经常递增和比较的令牌。基本上,对于每个请求$_SESSION['counter']++
在服务器端。也在浏览器端用 JS 做同样的事情(使用本地存储)。然后,当您发送请求时,只需获取令牌的随机数,并验证该随机数在服务器上是否相同。通过这样做,您应该能够检测到被劫持的会话,因为攻击者没有确切的计数器,或者如果他们有,您将有 2 个系统传输相同的计数,并且可以判断其中一个是伪造的。这并不适用于所有应用程序,但它是解决该问题的一种方法。
关于两者的注释
会话固定和劫持之间的区别仅在于会话标识符如何被泄露。在固定中,标识符被设置为攻击者事先知道的值。在劫持中,它要么是被猜测的,要么是从用户那里窃取的。否则,一旦标识符被泄露,两者的效果是相同的。
会话 ID 重新生成
每当您使用重新生成会话标识符时session_regenerate_id https://www.php.net/manual/en/function.session-regenerate-id.php应删除旧会话。这在核心会话处理程序中透明地发生。然而有些自定义会话处理程序使用session_set_save_handler() https://www.php.net/manual/en/function.session-set-save-handler.php不要这样做,并且容易受到旧会话标识符的攻击。如果您使用自定义会话处理程序,请确保跟踪您打开的标识符,如果它与您保存的标识符不同,请明确删除(或更改)旧标识符上的标识符。
使用默认的会话处理程序,您只需调用即可session_regenerate_id(true)
。这将为您删除旧的会话信息。旧 ID 不再有效,如果攻击者(或任何其他人)尝试使用它,将导致创建新会话。不过要小心自定义会话处理程序......
销毁会话
如果您要销毁会话(例如注销时),请确保彻底销毁它。这包括取消设置 cookie。使用session_destroy https://www.php.net/manual/en/function.session-destroy.php:
function destroySession() {
$params = session_get_cookie_params();
setcookie(session_name(), '', time() - 42000,
$params["path"], $params["domain"],
$params["secure"], $params["httponly"]
);
session_destroy();
}