简体   繁体   English

如何在Flask中安全地获取具有代理的用户IP地址?

[英]How do I safely get the user's ip address in Flask that has a proxy?

I am using Flask and need to get the user's IP address. 我正在使用Flask,需要获取用户的IP地址。 This is usually done through request.remote_addr but since this app is hosted at a 3rd party (and using cloudflare) it just returns the localhost. 这通常通过request.remote_addr完成,但由于此应用程序托管在第三方(并使用cloudflare),它只返回localhost。

Flask suggests getting the X-Forwarded-Host but then they immediately say it is a security risk. Flask建议获得X-Forwarded-Host ,然后他们立即说这是一个安全风险。 Is there a safe way to get the client's real ip? 有没有一种安全的方法来获得客户端真正的IP?

The Problem 问题

The issue here is not that the ProxyFix itself will cause the user to get access to your system, but rather the fact that the ProxyFix will take what was once mostly reliable information and replace it instead with potentially unreliable information. 这里的问题不是ProxyFix本身会导致用户访问您的系统,而是ProxyFix将采用曾经最可靠的信息并用可能不可靠的信息替换它。

For starters, when you don't use ProxyFix, the REMOTE_ADDR attribute is most likely retrieved from the source IP address in the TCP packets. 对于初学者,当您不使用ProxyFix时,很可能从TCP数据包中的源IP地址检索REMOTE_ADDR属性。 While not impossible, the source IP address in TCP packets are tough to spoof . 虽然并非不可能, 但TCP数据包中的源IP地址很难欺骗 Therefore, if you need a reliable way to retrieve the user's IP address, REMOTE_ADDR is a good way to do it; 因此,如果您需要一种可靠的方法来检索用户的IP地址,REMOTE_ADDR是一种很好的方法。 in most cases, you can rely on it to provide you something that is accurate when you do request.remote_addr . 在大多数情况下,当你发出request.remote_addr时,你可以依靠它为你提供准确的东西。

The problem is, of course, in a reverse-proxy situation the TCP connection is not coming from the end user; 当然,问题是在反向代理情况下,TCP连接不是来自最终用户; instead, the end user makes a TCP connection with the reverse proxy, and the reverse proxy then makes a second TCP connection with your web app. 相反,最终用户与反向代理建立TCP连接,然后反向代理与您的Web应用程序建立第二个TCP连接。 Therefore, the request.remote_addr in your app will have the IP address of the reverse proxy rather than the original user. 因此,应用中的request.remote_addr将具有反向代理的IP地址,而不是原始用户的IP地址。

A Potential Solution 潜在的解决方案

ProxyFix is supposed to solve this problem so that you can make request.remote_addr have the user's IP address rather than the proxy. ProxyFix应该解决这个问题,这样你就可以使request.remote_addr拥有用户的IP地址而不是代理。 It does this by looking at the typical HTTP header that remote proxies (like Apache and Nginx) add into the HTTP header ( X-Forwarded-For ) and use the user's IP address it finds there. 它通过查看远程代理(如Apache和Nginx)添加到HTTP标头( X-Forwarded-For )并使用其在那里找到的用户IP地址的典型HTTP标头来实现此目的。 Note that Cloudflare uses a different HTTP Header, so ProxyFix probably won't help you; 请注意,Cloudflare使用不同的HTTP标头,因此ProxyFix可能无法帮助您; you'll need to write your own implementation of this middleware to get request.remote_addr to use the original client's IP address. 您需要编写自己的中间件实现来获取request.remote_addr以使用原始客户端的IP地址。 However, in the rest of this answer I will continue to refer to that fix as "ProxyFix". 但是,在本答复的其余部分中,我将继续将该修复称为“ProxyFix”。

This solution, however, is problematic. 然而,该解决方案存在问题。 The problem is that while the TCP header is mostly reliable, the HTTP headers are not; 问题是虽然TCP标头最可靠,但HTTP标头不是; if a user can bypass your reverse proxy and send data right to the server, they can put whatever they want in the HTTP header. 如果用户可以绕过您的反向代理并将数据直接发送到服务器,他们可以在HTTP标头中放置他们想要的任何内容。 For example, they can make the IP address in the HTTP header the IP address of someone else! 例如,他们可以使HTTP头中的IP地址成为其​​他人的IP地址! If you use the IP address for authentication, the user can spoof that authentication mechanism. 如果使用IP地址进行身份验证,则用户可以欺骗该身份验证机制。 If you store the IP address in your database and then display it in your application to another user in HTML, the user could inject SQL or Javascript into the header, potentially causing SQL injection or XSS vulnerabilities. 如果将IP地址存储在数据库中,然后将其在应用程序中以HTML格式显示给另一个用户,则用户可能会将SQL或Javascript注入到标头中,从而可能导致SQL注入或XSS漏洞。

So, to summarize; 所以,总结一下; ProxyFix takes a known mostly-safe solution to retrieve the user's IP address from a TCP packet and switches it to using the not-very-safe-by-itself solution of parsing an easily-spoofed HTTP header. ProxyFix采用一种已知的最安全的解决方案,从TCP数据包中检索用户的IP地址,并使用解析易受欺骗的HTTP标头的非常安全的解决方案将其切换。

Therefore, the recomendation to use ProxyFix ONLY in reverse proxy situations means just that: don't use this if you accept connections from places that are NOT the proxy. 因此,在反向代理情况下仅使用ProxyFix的建议意味着:如果您接受来自非代理的位置的连接,请不要使用此方法。 This is often means have the reverse proxy (like Nginx or Apache) handle all your incoming traffic and have your application that actually uses ProxyFix safe behind a firewall. 这通常意味着让反向代理(如Nginx或Apache)处理所有传入流量,并让您的应用程序在防火墙后面实际使用ProxyFix。

You should also read this post which explains how ProxyFix was broken in the past ( although is now fixed ). 您还应该阅读这篇文章 ,其中解释了ProxyFix过去是如何被破坏的( 尽管现已修复 )。 This will also explains how ProxyFix works, and give you ideas on how to set your num_proxies argument . 这也将解释ProxyFix如何工作,并为您提供有关如何设置num_proxies参数的想法。

A Better Solution 更好的解决方案

Let's say your user is at point A, they send the request to Cloudflare (B) which eventually sends the request to your final application (point C). 假设您的用户位于A点,他们将请求发送到Cloudflare(B),最终将请求发送到您的最终应用程序(C点)。 Cloudflare will send the IP address of A in the CF-Connecting-IP header . Cloudflare将在CF-Connecting-IP header发送A的IP地址

As explained above, if the user finds the IP address to point C, they could send a specially crafted HTTP request directly to point C which includes any header info they want. 如上所述,如果用户找到指向C的IP地址,他们可以直接向C点发送特制的HTTP请求,其中包括他们想要的任何头信息。 ProxyFix will use its logic to determine what the IP address is from the HTTP header, which of course is problematic if you rely on that value for, well, mostly anything. ProxyFix将使用其逻辑来确定HTTP头中的IP地址,如果您依赖该值,那么这当然是有问题的。

Therefore, you might want to look at using something like mod_cloudflare , which allows you to do these proxy fixes directly in the Apache mod, but only when the HTTP connection comes from Cloudflare IP addresses (as defined by the TCP IP source). 因此,您可能希望查看类似mod_cloudflare的内容 ,它允许您直接在Apache mod中执行这些代理修复,但仅限于HTTP连接来自Cloudflare IP地址(由TCP IP源定义)。 You can also have it only accept connections from Cloudflare. 您也可以只接受来自Cloudflare的连接。 See How do I restore original visitor IP to my server logs for more info on this and help doing this with other servers (like Nginx). 有关详细信息,请参阅如何将原始访问者IP还原到我的服务器日志 ,并帮助其他服务器(如Nginx)执行此操作。

This should give you a start. 这应该给你一个开始。 However, keep in mind that you're still not "safe": you've only shut down one possible attack vector, and that attack vector assumed that the attacker knew the IP address of your actual application. 但是,请记住,您仍然不是“安全”:您只关闭了一个可能的攻击向量,并且该攻击向量假定攻击者知道您的实际应用程序的IP地址。 In that case, the malicious user could try to do a TCP attack with a spoofed Cloudflare IP address, although this would be extremely difficult . 在这种情况下,恶意用户可能会尝试使用欺骗性Cloudflare IP地址进行TCP攻击, 尽管这非常困难 More likely, if they wanted to cause havoc, they would just DDOS your source server since they've bypassed Cloudflare. 更有可能的是,如果他们想要造成严重破坏,他们只会DDOS你的源服务器,因为他们绕过了Cloudflare。 So, there are plenty more things to think about in securing, your application. 因此,在保护您的应用程序时还需要考虑更多的事情。 Hopefully this helps you with understanding how to make one part slightly safer. 希望这有助于您了解如何使一个部分更安全。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM