MVC / REST是否应为属于其他用户的资源返回403或404?


33

当使用基于资源的站点(例如MVC应用程序或REST服务)时,当客户端尝试GET访问他们无权访问的资源时,我们有两个主要选择:

  • 403,表示客户未经授权 ; 要么
  • 404,表示资源不存在(或无法找到)。

共同的智慧和惯例似乎是对事实做出回应-即403。但是我想知道这是否真的是正确的做法。

安全登录系统永远不会告诉您登录失败的原因。也就是说,就客户端而言,不存在的用户名和错误的密码之间没有可检测到的差异。目的是使用户ID(或更糟糕的是电子邮件地址)不易被发现。

隐私的角度来看,返回404似乎更安全。我想起了一起事件,据说有人通过查看真人秀(幸存者)中的哪些资源存在而找到了他们。网站与哪些网站做了。我担心403可能会泄露敏感信息,例如序列号或帐号。

是否有令人信服的理由返回404?404政策会在其他地方产生负面影响吗?如果没有,那为什么不更普遍呢?


1
令人信服的原因不返回404:如果服务关闭或身份验证中存在错误/错误,则您会得到404,但是尝试诊断问题的客户/用户/测试人员/开发人员/支持人员可能不知道错误消息出了什么问题。
史蒂文·埃弗斯

@Snorfus:很好,我已经回答了。尽管Josh确实已经添加了一个很好的对策……
Aaronaught 2011年

要记住的另一方面是:下游如何处理404?是否有CDN或某种缓存?如果您希望能够缓存它们,那么您可能不希望缓存“用户没有权限” 404。
pc1oad1etter

Answers:


15

有一个与之相关的普遍误解(和误用)403 Forbidden:不应泄露服务器对请求的看法。它是专门为说,

我能满足您的要求,但是无论您尝试什么,我都不会处理。因此,请停止尝试。

任何UA或客户应将其解释为意味着该请求将永远无法工作,并做出适当的响应。

这对客户端代表用户处理请求的含义是:如果用户未登录或输入错误,则处理请求的客户端应在第一时间后回复“对不起,但我无能为力”它获取403并停止处理将来的请求。显然,如果您希望用户在失败后仍然能够请求访问其个人信息,则这是对用户不利的行为。

403是相反的401 Authorization Required,这放弃服务器处理请求,只要你通过正确的凭据。这通常是人们听到声音时会想到的403

404 Page Not Found正如其他人所指出的,它也与之相反,该设计不仅被设计为说“我找不到该页面”,而且还向客户端建议服务器不为将来的请求声明成功或失败。

使用401404,服务器不会对客户端或UA透露任何处理方式:他们可以继续尝试,以期获得不同的响应。

因此404,处理不希望显示给所有人的页面的合适方法是,您不想放弃任何在某些情况下为什么不显示页面的信息。

当然,这假设发出请求的客户端关心小巧的RFC冗余。足够恶意的客户端将不会关心返回的状态码,除非是偶然的方式。通过将其与其他已知用户页面进行比较,就会知道它是一个隐藏用户页面(或潜在的隐藏用户页面)。

也就是说,假设您的处理程序是users/*。如果我知道users/foousers/barusers/baaz工作中,服务器返回401403404users/quux不意味着我不打算尝试一下,尤其是如果我有理由相信一个quux用户。一个标准的示例场景是Facebook:我的个人资料是私人的,但我对公开个人资料的评论不是。即使您返回404我的个人资料页面,恶意客户端也会知道我的存在。

因此,状态码不是针对恶意用例的,而是针对遵循规则的客户端的。对于那些客户,一个401或一个404请求是最合适的。


4
关于401与403的比较好点。不过,我不同意您对404声明的定论。当然,以Facebook为例,您已经知道quux存在。但是,并不总是会有外部证据,特别是在客户数据确实是私人的非社交网站上。一个多管闲事的或敌对的用户可能最终能够推断你在撒谎,但不一定哪个你在撒谎资源有关。我认为这里的重点是,除非没有其他可用的发现方法,否则不要费心404资源。
亚罗诺(Aaronaught)2011年

@Aaronaught问题是,您必须非常确实地确保有人无法弄清服务器的欺骗性,或者没有某种您没有强求的发现方法。足够聪明的人弄清楚这一点,此时状态码是没有意义的。

1
如果用户配置文件之间没有数据共享,那么我还不清楚如何足够聪明的人来解决这个问题。我知道有人确定最终会意识到“哦,404实际上意味着它可能存在,但我只是无法访问它”-但是假设服务器对于真正不存在的资源返回相同的错误,怎么办告诉不存在的资源和特权的资源之间的区别?
亚罗诺(Aaronaught)2011年

@Aaronaught唯一需要知道的是个人资料的URL应该存在。您可能只使用配置文件ID并以伪方式对其进行递增(因此,配置文件ID为3333的人并不意味着会有一个配置文件ID为3332的人),但是确定的人应该能够预测它有效ID的样本大小。失败了,即使给定一个完全强化的系统,也不会泄漏任何有关如何生成个人资料页面URL的信息,总会有社会工程学。

8

根据RFC2616

10.4.4 403禁止

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

还请注意,访问禁止资源时,授权无济于事


我知道RFC,尽管它与现实几乎没有相似之处。除了第一句话(“服务器理解了请求,但拒绝履行请求”。),几乎没有服务器能解释403的原因,而且大多数MVC框架甚至都具有HttpUnauthorizedResult旨在用于特权资源的类似东西。。我也意识到(显然)可以使用404 代替;我的问题是是否应该使用它,以及在做出决定时应该考虑什么。
亚罗诺(Aaronaught)2011年

@Aaronaught:RFC不仅允许您使用404,它还建议您在不想确认任何内容时抛出404。
Lie Ryan

3
很好,但是什么时候我不应该承认?还是应该在什么时候?这确实是问题的实质。
亚罗诺(Aaronaught)2011年

5

你应该?是的

你自己说的,尽量少出卖。如果我正在攻击系统,并且注意到服务器以403代码作为响应,则我将重点放在这些代码上,而不是继续前进。最好一扇门宣布它不存在,然后宣布它被禁止。

使用404请求的不利之处在于,它在外部看起来像该页面不存在,并且与应该存在但缺少的页面相比,这可能会有冲突。如果您不担心Web爬网程序(无论如何都应完全拒绝经过身份验证的系统),那么绝对应该这样做。我处理的每个API都以完全相同的方式处理未经授权的访问,StackOverflow也是如此。看不到该页面?我向您保证它确实存在,即使它声称存在。

已知资源存在并且访问被拒绝时,您应该确认请求。登录失败不应导致404消息。当资源本身的存在应受到保护时,您不应确认请求。对领域的访问存在于公共场所,但其中不存在安全组或角色。


令人信服的理由不返回404:如果服务关闭或身份验证中存在错误/错误,那么您会得到404,但是尝试诊断问题的客户/用户/测试人员/开发人员/支持人员可能不知道错误消息出了什么问题

开发人员应该有权访问日志,这将表明尝试访​​问受保护的资源。客户/用户/测试人员将生成反馈,最终反馈给开发人员。

默默无闻的安全...真的吗?

这不是默默无闻的安全措施。除了适当的安全措施之外,您还使用了模糊处理。

另一方面,获得“ 404”的有效请求只会增加不必要的复杂性和模糊性

它们不是有效的请求,它们是未经授权的请求。您只需更改一小部分(返回404而不是403)即可在任何可能的攻击者中获得实质性的优势。


默默无闻的安全...真的吗?如果有人试图出于恶意目的戳您的服务,那么他们已经知道该服务存在。另一方面,获得“ 404”的有效请求只会增加不必要的复杂性和模糊性。
史蒂文·埃弗斯

4
@Snorfus:在安全性隐私之间有一个微妙的区别。从定义上讲,隐私几乎就是“默默无闻”。这在基于资源的系统的上下文中尤其重要,因为资源的存在或不存在是潜在的重要信息。尽管我不太担心这些问题,但也可能会有安全方面的争论。我了解更多有关这种增加的复杂性的信息。除了您最初的评论,您还可以进一步详细介绍吗?(也许有一个更全面的答案?您被404版本403所咬吗?)
Aaronaught 2011年

2
@Snorfus:作为补充,我想补充一点,即纵深防御默默无闻的安全性并不相同。后者意味着没有其他保护手段。但是,在已经安全的系统中增加模糊性通常是一件好事-只要它不会在将来引起其他问题。在这种情况下,可以肯定的是系统已经被保护了,因为404是由授权代码发出的。
亚伦诺特2011年

@Aaronaught:我将发布更深入的答案,但要解决的问题是:如果资源是私有的,那么公开公开该资源的原因是什么?
史蒂文·埃弗斯

@Snorfus:资源是客户(或某个)的私有资源,而不是整个世界的私有资源。
亚罗诺(Aaronaught)2011年

0

这实际上取决于403状态代码给出的信息。如果您有一个API端点,GET /myresource/{id}当资源不存在时响应404,则当资源存在但未被当前用户授权时,端点返回的状态代码应取决于id参数的可预测性以及数量本身包含的信息。

  • 如果id是一个私有字段,例如电子邮件地址或银行帐号,则可能始终应将其隐藏在404后面。如果是电子邮件地址,它可能会阻止垃圾邮件程序漫游器编译已注册到您网站的有效电子邮件地址列表。
  • 如果id是公共用户名,请不要打扰,还有其他方法可以访问此信息(例如,仅通过浏览网站的论坛页面即可)。
  • 如果id是不透明但可预测的标识符(例如,一个自动递增的整数),则不会向攻击者泄露任何其他方式无法获得的信息。因此,我认为返回403状态代码是安全的。
  • 如果id是不透明且不可预测的标识符(如随机GUID),则问题会更加微妙。我个人认为返回403状态代码没有问题。仅当使用此ID的API中存在另一个有缺陷的端点时,才能利用此信息,但真正的缺陷是您的另一个端点。

在任何情况下,您可能都认为安全胜于遗憾,并且不管上下文如何都隐藏信息,但实际上您不能依靠这种类型的行为来提供任何形式的安全性。另一方面,它可以提供机密性(或隐私,就像其他人所说的那样)。

安全机制不应该只是攻击者的减速机,否则就毫无用处。在这种情况下,它甚至可能阻止您正确使用其他功能(爬网程序,Web应用程序防火墙正在寻找异常数量的403状态代码以阻止用户...)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.