检查引荐来源网址是否足以防范 CSRF 攻击?
检查引荐来源网址是否足以防止跨站点请求伪造攻击?我知道引荐来源网址可能会被欺骗,但是攻击者有没有办法为客户端做到这一点?我知道代币是常态,但这行得通吗?
Is checking the referrer enough to protect against a cross site request forgery attack? I know the referrer can be spoofed, but is there any way for the attacker to do that FOR the client? I know tokens are the norm, but would this work?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
这是一个 3 年前的问题,有四个不同的答案,基本上说明了同一件事:遵循规范,使用令牌,不要尝试使用引用者。
虽然令牌仍然被认为是最安全的选择,但使用引用者通常要容易得多,而且也非常安全。请务必查看所有 PUT/POST/PATCH/DELETE 请求,如果引用者丢失或来自错误的域,则将其视为攻击。很少有(如果有的话)代理会删除此类请求的引荐来源网址。
另请参阅OWASP 建议关于检查 Referer 标头作为 CSRF 保护:
This is a 3 year old question with four different answers basically stating the same thing: Follow the norm, use tokens, don't try to use referer.
While tokens still is considered the most secure option, using the referer is often a lot easier, and is also pretty secure. Just be sure to look at all PUT/POST/PATCH/DELETE-requests and consider it an attack if a referer is missing or from the wrong domain. Really few (if any) proxies remove the referer for these kinds of requests.
See also the OWASP recommendation about checking the referer header as a CSRF protection:
除此之外,对于浏览器(或公司代理)不发送引荐来源网址的用户来说,使用引荐来源网址将不起作用。
Among other things, using the referrer won't work for users whose browsers (or corporate proxies) don't send referrers.
唯一正确的答案是“除其他外,对于浏览器(或公司代理)不发送引荐来源网址的用户来说,使用引荐来源网址将不起作用。”话虽这么说,但这在当今是非常罕见的。所有说推荐人可以伪造的人都是这样说的。除非您以其他方式(XSS/特洛伊木马/等)控制其他人的浏览器,否则您无法伪造引荐来源网址。如果您需要使用引荐来源网址来使用应用程序,它们与 CSRF 令牌一样有效。只需确保您 100% 确保您的检查是正确的(例如,如果您使用正则表达式,请确保从引荐来源网址的开头“^”进行检查)。
The only correct answer is "Among other things, using the referrer won't work for users whose browsers (or corporate proxies) don't send referrers." That being said, that's highly uncommon nowadays. All the people saying that referrers can be faked are full of it. You cannot fake a referrer unless you have control over the other person's browser in some other way (XSS/Trojan/etc). If you require referrers for app use they are just as effective as CSRF Tokens. Just make sure you are making 100% sure that your check is correct (eg. if you are using regex make sure you check from the beginning "^" of the referrer).
是的。 如果你采取一些预防措施。
这是一个 12 年前的问题,是第一个出现的结果,所以我要回答它。在这12年里,事情发生了很大的变化。因此,虽然当时这可能是一个糟糕的选择,但现在它是一个易于实施且可靠的解决方案。
使用 Referrer 的主要疑问是请求中是否没有 Referrer 标头。这种情况可能会在多种情况下发生,例如攻击者省略引荐来源网址、从安全页面向不安全页面请求、代理或用户选择省略它或通过元标记省略它。
在上述所有情况下,如果没有有效的引荐来源网址,您应该严格忽略并失败请求。很明显,当攻击者省略标头时,您应该失败,并且您可以简单地不在页面的元标记中省略它。如果用户决定选择忽略它,那么这是他们的选择,并且会破坏功能,就像禁用 cookie 或 javascript 会破坏大多数网站一样。
从安全页面向不安全页面发送请求也不是什么大问题。因为在这12年里。网络已经发生了很大的变化,大多数网站根本不需要处理不安全的端点,实际上,如果您这样做,您将不会在地址栏中出现确保锁定的徽标。
谈到安全端点,也不用担心代理或 ISP 会省略标头,因为包括标头的整个请求都是加密的,拦截器根本无法检查标头,更不用说修改标头了,除非它们有权访问用户的设备,这总体上使得这种情况非常罕见。
但是推荐人不能被伪造吗?
伪造推荐人是一件既容易又困难的事情。它的可行性取决于您在此过程中信任的人。让我们考虑这个糟糕的策略:
用户登录网站
example.com
并example.com/login
检查用户是否是有效用户,然后将用户重定向到example .com/sensitive
后,example.com/sensitive
页面会评估引荐来源网址,如果它来自example.com/login
,则打印敏感数据。这很糟糕,因为用户可以轻松地在他/她自己的浏览器上伪造引荐来源网址。但防范 CSRF 攻击的整个想法并不适用于您不信任用户的情况。这是当您不信任用户真正发送的请求时使用的。这意味着为了伪造引荐来源网址,攻击者需要以某种方式修改用户的设备,老实说,如果攻击者具有该访问权限,他们毕竟不会费心发送第三方请求。那么,没什么可担心的?几乎。
我想到了两种棘手的情况,但都有简单的解决方案。
A。没有正确检查推荐人。这意味着什么?假设您的域名是
example.com
并且您只是检查example.com
是否存在于引荐字符串中。那么您可以错误地将example.com.evil.com
视为真实请求。解决方案是检查 SERVER_NAME 中的example.com/
,其中包括您的域名而不是整个地址。 (我在本地 PHP 服务器中检查了这一点,工作正常。您可能需要在自己的环境中进行测试,如果不适用,请找到另一个解决方案)B。考虑来自您自己网站的重定向。如果您的网站有一个端点可以重定向到外部资源,如下所示:
example.com/redirect?url=extenal.com
攻击者可以利用它并发出类似
example.com/redirect?url=example.com/sensitive
的请求来解决此问题,最好不要使用 GET 请求更改状态(修改数据库记录等) 。作为预防措施,您还可以检查请求是否来自您的重定向端点,并且不要在重定向端点中重定向到您自己的域。
Yes it is. if you take some precautions.
This is a 12 years old question which is first result to appear so i'm going to answer it. in this 12 years things has changed a lot. so while it could have been a poor choice back then, now it's an easy to implement and a reliable solution.
Main source of doubt about using referrer was if there was no referrer header in the request. this can happen in multiple occasions like attacker omitting referrer, requesting from a secure page to an insecure one, Proxies or users omitting it by choice or omitting it by meta tags.
in all cases above you should strictly ignore and fail requests without a valid referrer. it's obvious why you should fail when attacker omits the header and you can simply not omit it in meta tags in your page. if user decides to omit it by choice, well it's their choice and it will break functionality, just the way disabling cookies or javascript would break most websites.
Sending request from a secure page to an insecure one is not a big deal either. because in this 12 years. web has changed a lot and most websites don't need to deal with insecure endpoints at all actually if you do, you wont have that assuring lock logo appearing in the address bar.
Talking about secure endpoints, there is no worry about proxies or ISPs omitting the header either, because whole request including headers is encrypted and interceptors simply cant check headers let alone modify them unless they have access to user's device which overall makes it a very rare case.
But cant referrer be faked ?
Faking a referrer is a both easy and hard thing to do. it's feasibility depends on who you trust in the process. lets consider this awful strategy:
User logs in to website
example.com
andexample.com/login
checks if user is a valid user and then redirects user toexample.com/sensitive
, theexample.com/sensitive
page then evaluates referrer and if it is fromexample.com/login
, prints sensitive data. this is awful because user can easily fake the referrer on his/her own browser. but whole idea of protection against CSRF attack is not for cases when you don't trust the user. it's for when you don't trust the request to be genuinely sent from the user. which means in order to fake the referrer the attacker needs to somehow modify user's device and honestly if the attacker has that access they wont bother with sending third-party requests after all.So, nothing to worry about ? Almost.
there are two tricky situations with easy solutions that comes to mind.
A. not checking the referrer properly. what it means ? assuming that your domain is
example.com
and you are just checking whetherexample.com
exists in referrer string or not. then you can falsely considerexample.com.evil.com
as a genuine request. the solution is to check forexample.com/
in SERVER_NAME which includes your domain no the whole address. (i checked this in my local PHP server and worked fine. you might need to test with your own environment and find another solution if this is not applicable)B. Taking into account redirects from your own website. if your website has an endpoint to redirect to external resources like this :
example.com/redirect?url=extenal.com
an attacker can exploit it and make requests like this
example.com/redirect?url=example.com/sensitive
to solve this problem it's better not to change state (modifying database records, etc) with GET requests. as precautions you can also check if the request is from your redirect endpoint or not and also not to redirect to your own domain in your redirect endpoint.
不还不够,攻击者很容易为客户端执行此操作,正如您所要求的,攻击者所要做的就是让用户单击他创建的链接,从那时起,游戏就结束
了攻击者将复制原始站点中使用的表单,并欺骗其余部分,因为现在代码位于他自己的站点上,然后将其提交到受害者站点
正如您在问题中提到的那样,令牌是防止 CSRF 的标准
no is not enough, it is very easy for the attacker to do that FOR the client, as you ask, all the attacker has to do is get the user to click in a link created by him, from that point, is game over
The attacker will copy the form used in the original site, and spoof the rest because now the code is on his own site, then submit that to the victim site
As you mention on the question, tokens are the norm when it comes to prevent CSRF
遵循规范:使用代币。
检查引荐来源网址实际上没有任何作用,因为无论如何请求都是来自该页面!您试图防止的问题是在用户不执行任何操作的情况下请求页面;不是被点击的页面本身。
令牌是防止这种情况的方法。您生成一个,将其存储在会话中,并将其写入 HTML,然后在发布时检查您收到的内容,看看它是否与您期望的相匹配。如果没有,你就失败了。无论哪种方式,您都会在之后生成一个新的令牌。
还可能需要考虑的是,如果有多个页面,这会让人们感到困惑;所以你可能想为每个页面创建一个不同的令牌。
Follow the norm: use tokens.
Checking the referrer actually does nothing, because the request is coming from that page anyway! The problem you are trying to prevent is the page being requested without the user doing anything; not the page being hit itself.
Tokens are the way to protect against this. You generate one, store it in the session, and write it to the HTML, then, upon posting, you check the one you receive, and see if it matches the one you expect. If it doesn't, you fail. Either way, you generate a new token afterwards.
It may also be relevant to consider that this will mess people up if the have multiple pages; so you may like to make a different token per page.