我一直在寻找防止会话劫持的方法,即有人窃取会话cookie并使用它来访问系统。
诸如http://codebutler.com/firesheep使在开放的无线网络上嗅探会话变得容易,其他获取会话的方法包括跨站点脚本攻击,或者只是从受害者的计算机上物理地获取会话。
使用SSL保护所有会话cookie/服务器通信对于防止Firesheep嗅探至关重要,在cookie上设置HTTPOnly有助于防止JavaScript在XSS攻击中读取会话cookie,但它仍然容易受到基于AJAX的攻击。
另一层是在会话cookie中包含一个安全令牌或随机数,该会话cookie在每次请求时都会更新。您将令牌存储在服务器端数据存储区和cookie中,并在每次请求时比较cookie中的令牌与数据存储区中的令牌是否匹配。
如果令牌不匹配,这可能表明有人窃取了会话并试图使用它,因此您可以忽略请求或使会话无效,并要求用户重新进行身份验证。但是,不匹配的令牌也可能是由于连接缓慢/不稳定造成的。
例如,您可能会遇到这样的情况:服务器接收来自真实用户的请求,更新服务器数据存储中的会话令牌,并使用包含更新令牌的会话cookie来响应用户。但是,由于连接缓慢/不稳定,用户没有收到响应,因此用户仍然拥有旧的会话令牌,而新的会话令牌存储在服务器上。当用户重试请求时,令牌将不匹配。
缓解这个问题的一种方法是,服务器保留最后几个令牌的历史记录,并检查它们是否匹配,但随后就变成了要保留多少令牌的情况,根据连接的脆弱性或用户的点击率,服务器可能会在连接恢复和浏览器更新用户会话之前循环浏览历史记录。
保存令牌历史的另一种选择是给每个会话加上时间戳,并检查时间戳是否在某个短的指定范围内,比如30秒。如果用户的会话cookie时间戳在服务器存储的会话时间戳的30秒内,则该会话被认为是可信的。
伪代码示例
def authenticate_request():
if (stored_session.timestamp - session.timestamp > 30 seconds):
return False
return True
这避免了必须保留令牌历史记录(时间戳成为令牌),但攻击者在会话被盗后有30秒的机会劫持会话。虽然这是真的,但代币历史记录替代方案并没有更好,因为它给了攻击者更长的机会窗口。
检查IP地址和用户代理更改的其他方法也存在问题。用户代理很容易被欺骗,如果攻击者能够获得用户的会话,他们可以通过相同的XSS代码或其他方式轻松确定用户代理。
如果用户在移动设备上,他们的IP地址可能会频繁更改,从而导致许多误报。此外,攻击者可能在同一家公司的防火墙后面,因此用户和攻击者的IP与外部Web服务器相同。
使用时间戳令牌是正确的方法还是有更好的方法?30秒的缓冲时间差不多吗?我遗漏了哪些边缘案例?
我不知道时间戳是如何工作的。它要求用户在向服务器发送另一个请求之前,在一个页面上花费的时间永远不要超过30秒。我确信我花了超过30秒的时间阅读这个页面,并在按下"Post"之前键入这个回复。
在我看来,这是一个固有的问题,你通过线路发送的任何数据都可能被拦截和复制。加密密码并不能解决问题,因为黑客可以拦截加密的值,然后发送加密的值。他不一定关心未加密的值是什么
你发送的任何代币都是一样的。黑客可以拦截并复制令牌。
我听到的唯一一个似乎可以解决这个问题的想法是使用公钥和私钥的挑战和响应系统:a创建一个随机字符串,使用B的公钥加密,然后将其发送给B。B使用他的私钥解密该字符串,并将解密后的值与他的应用程序数据一起发送回。然后,A验证解密后的值是否与原始值匹配。如果没有验证,他会拒绝相关的数据。
如果黑客不知道B的私钥,他就无法拦截来自A的消息并伪造响应。黑客不能使用之前从B截获的回复,因为每次随机字符串都不同。