在网络安全领域,正确使用HTTP状态码至关重要。然而,许多人在没有充分考虑安全问题的情况下,会根据一些建议使用401和403状态码。建议通常是这样的:当访问令牌未提供或无效时使用401,当访问令牌有效但需要更多权限时使用403。这种实施可能会导致敏感信息泄露,从而引发严重的安全问题。
在密码学中,这种现象被称为“预言机”(oracle),它可能导致严重的攻击。如果攻击者在多次401状态码失败尝试后看到一个403状态码,这意味着攻击者尝试的令牌通过了身份验证阶段,但未能通过授权。这样,攻击者就可能猜到了一组有效的凭证(或令牌等),而系统以“明文”告诉了他们。这类似于“用户名或密码无效”的最佳实践,但请不要阅读类似这样的内容。
为了避免这个问题,应该坚持使用一个状态码(例如,403)来处理两种情况(身份验证失败和授权失败),避免过于用户(或客户端)友好。可以记录事件,并返回一个唯一的请求ID给客户端。如果真正的客户端报告问题,那么请求ID应该有助于在日志中找到更多详细信息。当然,还要跟踪/监控所有身份验证/授权失败事件,以进行异常检测。
现在,让以数学证明的形式来讨论上述内容。假设一个系统中可能的最大凭证数量为N,注册用户数量为M,其中K个用户可以访问攻击者试图暴力破解的特定资源,满足N > M ≥ K。考虑以下命题/事件:
A - 通过访问给定资源来猜测凭证。
B - 系统设计为:对于有权限访问资源的有效凭证返回HTTP 200,对于没有权限访问资源的有效凭证返回HTTP 403,对于无效凭证返回HTTP 401。简而言之,B = {200} ∪ {403} ∪ {401}。
C - 系统设计为:对于有权限访问资源的有效凭证返回HTTP 200,对于没有权限访问资源的有效凭证或无效凭证返回HTTP 403。换句话说,C = {200} ∪ {403}。
换句话说:
在B条件下,A的基数是:K个可能的HTTP 200情况,加上M-K个可能的HTTP 403情况。总计为M。
在C条件下,A的基数是:K个可能的HTTP 200情况,这也是总计。
现在让计算概率:
P(A | B) = M / N
P(A | C) = K / N
显然(因为M ≥ K):
P(A | B) ≥ P(A | C)