好的,有两个独立但相关的问题,每个问题的处理方式都不相同。
会话固定
攻击者在此处为用户明确设置会话的会话标识符。通常在PHP中,是通过给他们提供url这样的方式来完成的http://www.example.com/index...?session_name=sessionid
。一旦攻击者将URL提供给客户端,攻击就与会话劫持攻击相同。
有几种方法可以防止会话固定(全部完成):
会话劫持
在这里,攻击者可以获取会话标识符,并能够像发送该用户一样发送请求。这意味着,由于攻击者具有标识符,因此就服务器而言,它们几乎与有效用户没有区别。
您不能直接阻止会话劫持。但是,您可以采取措施使其变得非常困难和难以使用。
使用强会话哈希标识符:session.hash_function
中php.ini
。如果PHP <5.3,则将其设置session.hash_function = 1
为SHA1。如果PHP> = 5.3,请将其设置为session.hash_function = sha256
或session.hash_function = sha512
。
发送一个强大的哈希值:session.hash_bits_per_character
中php.ini
。将此设置为session.hash_bits_per_character = 5
。尽管这不会使破解变得更加困难,但在攻击者试图猜测会话标识符时,确实有所作为。ID将更短,但使用更多字符。
使用session.entropy_file
和session.entropy_length
在php.ini
文件中设置附加的熵。例如,将前者设置为session.entropy_file = /dev/urandom
,将后者设置为将从熵文件中读取的字节数session.entropy_length = 256
。
从默认的PHPSESSID更改会话的名称。这是通过在调用之前session_name()
使用您自己的标识符名称作为第一个参数来完成的session_start
。
如果您确实很偏执,也可以旋转会话名称,但是请注意,如果更改此名称,则所有会话将自动失效(例如,如果您依赖于时间)。但是根据您的用例,它可能是一个选择...
经常轮换您的会话标识符。我不会对每个请求都执行此操作(除非您确实需要该级别的安全性),而是以随机间隔进行。您希望经常更改此设置,因为如果攻击者确实劫持了会话,则您不希望他们能够使用它太长时间。
在会话中包括用户代理$_SERVER['HTTP_USER_AGENT']
。基本上,当会话开始时,将其存储在$_SESSION['user_agent']
。然后,在每个后续请求上检查其是否匹配。请注意,这可能是伪造的,因此并非100%可靠,但总比没有好。
在会话中包括用户的IP地址$_SERVER['REMOTE_ADDR']
。基本上,当会话开始时,将其存储在$_SESSION['remote_ip']
。对于某些为其用户使用多个IP地址的ISP(例如曾经使用过的AOL),这可能会出现问题。但是,如果使用它,它将更加安全。攻击者伪造IP地址的唯一方法是在真实用户和您之间的某个时候破坏网络。而且,如果它们危害了网络,它们的后果可能远不如劫持(例如MITM攻击等)。
在会话中以及您经常增加和比较的浏览器端添加令牌。基本上,对于每个请求都$_SESSION['counter']++
在服务器端执行。也可以在浏览器端的JS中执行某些操作(使用本地存储)。然后,当您发送请求时,只需简单地获取令牌的现时值,并验证该现时值在服务器上是否相同。这样,由于攻击者将没有确切的计数器,因此您应该能够检测到被劫持的会话,或者如果攻击者没有,您将有2个系统传输相同的计数并可以辨别出一个伪造的系统。这不适用于所有应用程序,但这是解决问题的一种方法。
关于两者的说明
会话固定和劫持之间的区别仅在于如何损害会话标识符。在固定中,将标识符设置为攻击者事先知道的值。在“劫持”中,它是被用户猜测或被盗的。否则,一旦标识符受损,两者的作用是相同的。
会话ID再生
每当您使用session_regenerate_id
旧会话重新生成会话标识符时,都应将其删除。这对于核心会话处理程序是透明的。但是,某些使用的自定义会话处理程序session_set_save_handler()
不会执行此操作,因此很容易攻击旧的会话标识符。如果使用的是自定义会话处理程序,请确保跟踪打开的标识符,如果保存的标识符与保存的标识符不同,则请在旧标识符上显式删除(或更改)标识符。
使用默认的会话处理程序,只需调用即可session_regenerate_id(true)
。这将为您删除旧的会话信息。旧的ID不再有效,如果攻击者(或与此有关的任何其他人)尝试使用它,它将导致创建新的会话。但是请谨慎使用自定义会话处理程序。
销毁会话
如果要销毁会话(例如,注销时),请确保彻底销毁它。这包括取消设置cookie。使用session_destroy
:
function destroySession() {
$params = session_get_cookie_params();
setcookie(session_name(), '', time() - 42000,
$params["path"], $params["domain"],
$params["secure"], $params["httponly"]
);
session_destroy();
}