更新
我们最终与Acunetix团队的一些程序员举行了一次会议,他们意识到他们的代码中可能存在一些错误,导致扫描中显示的问题比实际情况更严重。普遍的共识是忽略扫描结果,使用开箱即用的ASP.NET会话ID生成,因为它对我们的网站来说应该足够安全。
@Vasile Bujac,因为你的答案是唯一的,并且提到使用ASP.NET标准解决方案,所以我认为这是答案,但感谢大家的帮助。
我们在工作中使用Acunetix的视网膜扫描仪对我们的应用程序进行安全扫描。它告诉我们,我们的会话ID不够随机,也太可预测了。我不太确定ASP.NET默认情况下是如何生成会话ID的(我认为它是GUID?),但我继续实现了扩展SessionIDManager类并重写CreateSessionID和Validate方法以使用GUID的方法,如MSDN文章中所述。
虽然这使它稍微更随机,但根据Acunetix的说法,它仍然没有产生"想要的"效果。我甚至在web.config中添加了regenerateExpiredSessionId="true"
属性,但没有任何效果。我有一种感觉,我可能需要故意调用Session.Abandon()
来真正清除会话并获得新的ID。问题是,我必须在用户登录之前立即调用它,因为这是知道用户正在启动新会话的唯一防故障方法。因此,在下一个页面以Abandon
方法的工作方式加载之前,我无法在会话中设置任何内容,这意味着一个介于两者之间的页面,这不是很理想,但可以做到。
有人经历过这种情况或成功实施了修复吗?
此外,仅供参考,我们不使用成员身份/表单身份验证,我们只是在有人登录时创建一个新的自定义用户类,并将其保存在会话中以备将来使用。
Acunetix的报告:
CWE-330第59页OWASP2007-A7
描述:表现出低熵("随机性")的会话令牌通常容易受到预测攻击。不安全令牌可能是由于伪随机数生成器、基于时间的值、静态值或基于用户属性(用户名或用户ID)的值不足。这意味着,攻击者可以在短时间内监视应用程序并收集其创建的会话令牌后,猜测有效的会话令牌。如果攻击者确定了另一个用户的有效会话令牌,则可以查看、修改或删除任意用户的数据,而无需猜测受害者的用户名或密码。因此,推断有效会话令牌的能力使攻击者能够绕过登录页面,从而无需使用暴力帐户。此外,即使受害者当前未登录到应用程序,静态令牌也可以使攻击者以用户为目标。这增加了攻击者可以攻击的受害者数量。
会话令牌应该使用强随机数生成器创建,并从大量数字池中收集。例如,如果操作系统的rand()函数能够产生统计上均匀分布的32位值,那么它通常就足够了。较差的会话令牌是增量的,依赖于用户的帐户ID,只使用时间戳,或者具有其他高度确定性的信息。保护会话令牌安全的其他方法是始终通过SSL传输令牌,在一段时间后自动使令牌过期,以及每当用户注销应用程序时显式使令牌过期。
建议:如果会话值表现出很强的随机性,但是从一个小的值池中选择的,则攻击者更有可能简单地猜测有效令牌。web应用程序的会话管理可以通过实现以下几种互补技术来改进:
- 请确保Token值的大小至少为32位,尤其是对于具有大量并发用户和高每日页面请求量的应用程序
- 熵源的比特大小(随机值)比实际会话令牌的比特大小更重要。例如,MD5散列产生一个128位的值。然而,增量值的MD5散列、时间戳或8位随机数都是不安全的,因为随机值的来源可以很容易地预测。因此,128比特的大小并不表示会话令牌的准确度量。熵源的最小大小是32位,尽管对于每小时并发用户超过10000的站点可能需要更大的池(48或64位)
- 在大多数情况下,应用程序生成的令牌(例如ASP.NET_SessionId、ASPSESSIONID、JSPSSIONID、PHPSESSIONID)提供足够大的随机值来防止会话预测攻击。除非对自定义会话机制进行了彻底的审查和测试,否则应用程序应该使用这些会话管理算法
- 使用服务器端对象跟踪与会话令牌关联的用户属性,以防止用户模拟攻击。如果应用程序没有将用户的会话令牌与该用户的配置文件信息严格关联,则攻击者可能能够通过操纵客户端值来查看任意信息。例如,如果应用程序设置了强会话令牌,但基于"UserId"cookie执行SQL查询,则攻击者只需要修改"UserId"cookie即可模拟其他人。如果应用程序将"UserId"值与服务器端会话对象相关联,则会更安全,因为攻击者无法修改该值
- 当用户注销应用程序或在预定的不活动时间段之后,使会话令牌过期。我们建议对会话令牌使用20分钟的超时,尽管这在很大程度上取决于应用程序的类型和预期使用情况
我记得,ASP.NET会话id生成器为会话预测提供了很好的保护。会话id有24个字符,使用[a-z]个字符和[0-5]个数字(总共32个可能的字符,即2^5),总共给出2^(5*24)=2^120个可能的值。然而,您可以实现SessionIDManager来附加一些信息(如用户主机地址、用户代理、使用HMAC算法的验证令牌),以获得更好的保护,这样来自不同IP地址或不同浏览器的会话id就不会通过验证。如果您已经实现了表单身份验证,那么这是不必要的,因为身份验证票证已经提供了这些类型的保护。
如果你想要更好的随机会话id,你可以在SessionIDManager中使用RandomNumberGenerator,如RNGCryptoServiceProvider,并填充一堆字节(比如32,即256位),然后使用Base64 对其进行编码
byte[] random = new byte[100];
//RNGCryptoServiceProvider is an implementation of a random number generator.
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(random); // The array is now filled with cryptographically strong random bytes.
return Convert.ToBase64String(random)
然而,本文指出,会话id的最大长度是80,因此您也必须覆盖Validate方法才能使其工作。