403 禁止 vs 401 未经授权的 HTTP 响应

对于存在的网页,但用户没有足够特权(他们没有登录或不属于适当的用户组)的网页,可以提供什么适当的 HTTP 响应?

401 Unauthorized
403 Forbidden吗?
还有吗

到目前为止,我对两者的区别还不清楚。每种使用情况适合哪些用例?

答案

Daniel Irvine 的明确解释:

401 Unauthorized出现问题,身份验证错误的 HTTP 状态代码。就是这样:它用于身份验证,而不是授权。收到 401 响应的服务器会告诉您:“您未通过身份验证 - 完全没有身份验证或身份验证不正确 - 但请重新进行身份验证并重试。” 为了帮助您,它将始终包含一个WWW-Authenticate标头,该标头描述了如何验证。

这是通常由您的 Web 服务器而不是 Web 应用程序返回的响应。

这也是非常临时的。服务器要求您重试。

因此,对于授权,我使用403 禁止响应。它是永久的,与我的应用程序逻辑相关,并且比 401 更具体。

服务器收到 403 响应,告诉您:“很抱歉。我知道您是谁 - 我相信您说的是谁 - 但您只是没有访问此资源的权限。也许如果您很好地询问系统管理员,您将获得许可。但是请不要再困扰我,直到您的困境改变为止。”

总之,当用户通过身份验证但无权对给定资源执行请求的操作时,应使用401 未经授权的响应来进行丢失或错误的身份验证,然后使用403 禁止响应。

另一种不错的图片格式 ,说明应如何使用 http 状态代码。

在此处输入图片说明

参见RFC2616

401 未经授权:

如果请求已包含授权凭证,则 401 响应指示已拒绝这些凭证的授权。

403 禁止:

服务器理解了该请求,但拒绝执行该请求。

更新资料

从您的用例来看,似乎用户未通过身份验证。我会返回 401。


编辑: RFC2616已过时,请参阅RFC7231RFC7235

缺少其他答案的是,必须理解,在 RFC 2616 上下文中的身份验证和授权仅引用 RFC 2617 的 HTTP 身份验证协议。HTTP 状态码不支持通过 RFC2617 之外的方案进行身份验证,因此不考虑在决定使用 401 还是 403 时。

简明扼要

未经授权表示客户端未通过 RFC2617 认证,服务器正在启动认证过程。 “禁止” 表示客户端已通过 RFC2617 认证并且没有授权,或者服务器不支持所请求资源的 RFC2617。

这意味着,如果您有自己的自备登录过程并且从不使用 HTTP 身份验证,则 403 始终是正确的响应,并且永远不应该使用 401。

详细和深入

从 RFC2616

10.4.2 401 未经授权

该请求需要用户认证。响应必须包括一个 WWW-Authenticate 头域(第 14.47 节),该头域包含适用于所请求资源的质询。客户可以用合适的授权头域(第 14.8 节)重复请求。

10.4.4 403 禁止服务器理解了请求,但拒绝执行。授权将无济于事,不应重复该请求。

首先要记住的是,本文档中的 “身份验证” 和 “授权” 是专门指 RFC 2617 中的 HTTP 身份验证协议。它们不涉及您可能创建的任何自带身份验证协议使用登录页面等。我将使用 “登录” 来指通过 RFC2617 以外的方法进行身份验证和授权

因此,真正的区别不在于问题是什么,甚至不是解决方案。区别在于服务器希望客户端接下来执行的操作。

401 指示无法提供资源,但是服务器正在请求客户端通过 HTTP 身份验证登录,并已发送了回复标头以启动该过程。可能有一些授权将允许访问该资源,也许没有,但是让我们尝试一下看看会发生什么。

403 表示无法提供资源,对于当前用户,没有办法通过 RFC2617 解决此问题,也没有尝试的意义。这可能是因为已知没有足够的身份验证级别(例如,由于 IP 黑名单),但是可能是因为用户已经通过身份验证并且没有权限。 RFC2617 模型是一个单用户单凭证,因此可以忽略用户可能拥有第二组可以授权的凭证的情况。它既不暗示也不暗示某种登录页面或其他非 RFC2617 身份验证协议可能会或可能不会有所帮助 - 这超出了 RFC2616 标准和定义。


编辑: RFC2616已过时,请参阅RFC7231RFC7235

Resource exists ? (if private it is often checked AFTER auth check)
    |       |
 NO |       | YES
    v       v
   404      Is logged-in ? (authenticated, aka has session)
   or         |              |
   401     NO |              | YES
   403        |              |
              v              v
              401            Can access resource ? (permission, authorized) ?
         (404 no reveal)      |            |
             or            NO |            | YES
             redirect         |            |
             to login         v            v
                              403          OK 200, redirect, ...
                      (or 404: no reveal)

通常按以下顺序进行检查:

  • 401(如果未登录或会话已过期)
  • 403,如果用户无权访问资源(文件,json,...)
  • 404(如果资源不存在(或不愿透露任何内容))

UNAUTHORIZED :状态码(401),指示请求需要身份验证 ,通常这意味着用户需要登录(会话)。服务器未知的用户 / 代理。可以重复使用其他凭据。注意:这令人困惑,因为它应该被命名为 “未经身份验证” 而不是 “未经授权”。如果会话过期,登录后也可能发生这种情况。特殊情况:可以代替 404 使用,以避免显示资源的存在或不存在(信用 @gingerCodeNinja)

禁止 :状态代码(403)指示服务器理解了该请求,但拒绝执行该请求。服务器已知的用户 / 代理,但凭据不足 。除非更改凭据,否则重复请求将不起作用,这在很短的时间内是非常不可能的。特殊情况:可以代替 404 使用,以避免显示资源的存在或不存在(信用 @gingerCodeNinja)

未找到 :状态代码(404),指示请求的资源不可用。用户 / 代理已知,但服务器不会显示任何有关资源的信息,就像不存在该信息一样。重复将不起作用。这是 404 的一种特殊用法(例如 github)。

如 @ChrisH 所提到的,有一些重定向选项(301、302、303、307 或根本不重定向并使用 401):

根据RFC 2616 (HTTP / 1.1),在以下情况下发送 403:

服务器理解了该请求,但拒绝执行该请求。授权将无济于事,不应重复该请求。如果请求方法不是 HEAD,并且服务器希望公开为什么未满足请求,则应在实体中描述拒绝原因。如果服务器不希望将此信息提供给客户端,则可以使用状态代码 404(未找到)代替

换句话说,如果客户端可以通过身份验证访问资源,则应发送 401。

假设 HTTP 认证 (WWW 身份验证授权头) 在使用中 ,如果认证作为另一个用户将授予访问所请求的资源,那么 401 未授权应返回。

403 Forbidden 用于禁止所有人访问资源或限制访问给定网络或仅通过 SSL 允许访问资源,只要与 HTTP 身份验证无关即可。

如果未使用 HTTP 身份验证,并且按当今的标准为基于 cookie 的身份验证服务提供服务,则应返回 403 或 404。

关于 401,这来自 RFC 7235(超文本传输协议(HTTP / 1.1):身份验证):

3.1。 401 未经授权

401(未经授权)状态码表示该请求尚未应用,因为它缺少针对目标资源的有效身份验证凭据。源服务器必须发送一个包含至少一个适用于目标资源的质询的 WWW-Authenticate 头域(第 4.4 节)。 如果请求包括认证证书,则 401 响应指示已拒绝那些证书的授权 。客户端可以用一个新的或替换的 Authorization 头域(4.1 节)重复请求。如果 401 响应包含与先前响应相同的质询,并且用户代理已经尝试了至少一次身份验证,则用户代理应该向用户呈现随附的表示,因为它通常包含相关的诊断信息。

403(和 404)的语义已随时间而改变。这是从 1999(RFC 2616)开始的:

10.4.4 403 禁止

服务器理解了该请求,但拒绝执行该请求。
授权将无济于事 ,不应重复该请求。
如果请求方法不是 HEAD 并且服务器希望执行
公开为什么请求没有得到满足,应该在实体中描述拒绝的原因。如果服务器不希望将此信息提供给客户端,则状态码为 404
(未找到)可以代替使用。

2014 年,RFC 7231(超文本传输协议(HTTP / 1.1):语义和内容)更改了 403 的含义:

6.5.3。 403 禁止

403(禁止)状态码表示服务器理解了请求,但拒绝授权。希望公开为什么禁止请求的服务器可以在响应有效负载(如果有)中描述该原因。

如果请求中提供了身份验证凭据,则
服务器认为它们不足以授予访问权限。客户端
不应自动将相同的请求重复
证书。客户端可以用新的或不同的证书重复请求。但是,出于某些原因,请求可能被禁止
与凭据无关。

希望 “隐藏” 当前存在的原始服务器
禁止的目标资源可能会以状态码回应
404(未找到)。

因此,403(或 404)现在可能意味着任何事情。提供新的凭据可能会有所帮助... 或可能没有帮助。

我相信这已经改变的原因是 RFC 2616 假定在当今的 Web 应用程序在实践中使用例如表单和 cookie 构建自定义身份验证方案时将使用 HTTP 身份验证。

这是一个比较老的问题,但是从未真正提出过的一种选择是返回 404。从安全角度来看,投票率最高的答案有潜在的信息泄漏漏洞 。例如,假设所讨论的安全网页是系统管理员页面,或更常见的是,是用户无法访问的系统中的记录。理想情况下,您甚至不希望恶意用户知道那里有一个页面 / 记录,更不用说他们没有访问权限了。当我构建类似这样的东西时,我将尝试在内部日志中记录未认证 / 未授权的请求,但返回 404。

OWASP 提供了有关攻击者如何在攻击过程中使用此类信息的更多信息

这个问题是在不久前提出的,但是人们的想法在不断发展。

该草案(由 Fielding 和 Reschke 撰写)的6.5.3 节为状态代码 403 赋予了与RFC 2616 中所记录的含义稍有不同的含义。

它反映了许多流行的 Web 服务器和框架采用的身份验证和授权方案中发生的情况。

我强调了我认为最突出的一点。

6.5.3。 403 禁止

403(禁止)状态码表示服务器理解了请求,但拒绝授权。希望公开为什么禁止请求的服务器可以在响应有效负载(如果有)中描述该原因。

如果请求中提供了身份验证凭据,则服务器认为它们不足以授予访问权限。 客户端不应使用相同的凭证重复请求。客户端可以用新的或不同的证书重复请求。但是,出于与凭据无关的原因,可能会禁止请求。

希望 “隐藏” 当前存在的禁止目标资源的原始服务器可以使用状态代码 404(未找到)进行响应。

无论使用哪种约定,重要的是要在整个站点 / API 之间提供统一性。

TL; DR

  • 401:与身份验证有关的拒绝
  • 403:与身份验证无关的拒绝

实际例子

如果apache 需要验证 (通过.htaccess ),并且您单击Cancel ,它将以401 Authorization Required响应。

如果nginx找到文件,但是没有读取 / 访问该文件的访问权限 (用户 / 组),它将以403 Forbidden响应

RFC(2616 第 10 节)

401 未经授权(10.4.2)

含义 1: 需要认证

该请求需要用户认证。 ...

含义 2: 认证不足

... 如果请求已包含授权凭证,则 401 响应指示已拒绝这些凭证的授权。 ...

403 禁止(10.4.4)

含义: 与身份验证无关

... 授权将无济于事...

更多细节:

  • 服务器理解了该请求,但拒绝执行该请求。

  • 它应该描述实体拒绝的原因

  • 可以使用状态代码 404(未找到)

    (如果服务器希望从客户端保留此信息)

他们没有登录或不属于正确的用户组

您陈述了两种不同的情况;每种情况应有不同的响应:

  1. 如果根本没有登录,则应返回401 未经授权
  2. 如果他们已登录但不属于正确的用户组,则应返回403 Forbidden

根据对此答案收到的评论,在 RFC 上进行说明:

如果用户未登录,则他们未经身份验证,其 HTTP 等效项是 401,并且在 RFC 中被误称为 “未经授权”。如第 10.4.2 节所述,针对401 未经授权

“该请求需要用户验证 。”

如果您未经身份验证,则 401 是正确的响应。但是,如果您未经授权,则从语义上正确的意义上来说,403 是正确的响应。