<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Fri, Mar 17, 2017 at 2:52 AM, Ilya Skriblovsky <span dir="ltr"><<a href="mailto:ilyaskriblovsky@gmail.com" target="_blank">ilyaskriblovsky@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><span class="gmail-m_388361609629121005gmail-"><div dir="ltr" class="gmail-m_388361609629121005gmail-m_-525099954024514115gmail_msg">> <span style="color:rgb(33,33,33)" class="gmail-m_388361609629121005gmail-m_-525099954024514115gmail_msg">The code calling request.URLPath(), in a given Resource, or application, is highly unlikely to know whether it wants to honor (x-)forwarded-for.</span></div></span><div dir="ltr" class="gmail-m_388361609629121005gmail-m_-525099954024514115gmail_msg"><div class="gmail-m_388361609629121005gmail-m_-525099954024514115gmail_msg"><span style="color:rgb(33,33,33)" class="gmail-m_388361609629121005gmail-m_-525099954024514115gmail_msg">You are right, I haven't thought about it.</span></div><div class="gmail-m_388361609629121005gmail-m_-525099954024514115gmail_msg"><span style="color:rgb(33,33,33)" class="gmail-m_388361609629121005gmail-m_-525099954024514115gmail_msg">But I'm in doubt whether trusting X-Forwarded-* by default can damage security if Twisted app is running with naked HTTP(S) port exposed without reverse proxy that handles these headers.</span></div><div class="gmail-m_388361609629121005gmail-m_-525099954024514115gmail_msg"><span style="color:rgb(33,33,33)" class="gmail-m_388361609629121005gmail-m_-525099954024514115gmail_msg">There are three headers:</span></div><div class="gmail-m_388361609629121005gmail-m_-525099954024514115gmail_msg"><span style="color:rgb(33,33,33)" class="gmail-m_388361609629121005gmail-m_-525099954024514115gmail_msg">1. X-Forwarded-For specifying original client IP and IPs of proxies</span></div><div class="gmail-m_388361609629121005gmail-m_-525099954024514115gmail_msg"><span style="color:rgb(33,33,33)" class="gmail-m_388361609629121005gmail-m_-525099954024514115gmail_msg">2. X-Forwarded-Host specifying original Host header from the client</span></div><div class="gmail-m_388361609629121005gmail-m_-525099954024514115gmail_msg"><span style="color:rgb(33,33,33)" class="gmail-m_388361609629121005gmail-m_-525099954024514115gmail_msg">3. X-Forwarded-Proto specifying original client's scheme</span></div><div class="gmail-m_388361609629121005gmail-m_-525099954024514115gmail_msg"><span style="color:rgb(33,33,33)" class="gmail-m_388361609629121005gmail-m_-525099954024514115gmail_msg">(there is also new-style "Forwarded:" header but it is not widely used yet, AFAIK)</span></div><div class="gmail-m_388361609629121005gmail-m_-525099954024514115gmail_msg"><span style="color:rgb(33,33,33)" class="gmail-m_388361609629121005gmail-m_-525099954024514115gmail_msg"><br class="gmail-m_388361609629121005gmail-m_-525099954024514115gmail_msg"></span></div><div class="gmail-m_388361609629121005gmail-m_-525099954024514115gmail_msg"><span style="color:rgb(33,33,33)" class="gmail-m_388361609629121005gmail-m_-525099954024514115gmail_msg">X-Forwarded-For definetly can't be trusted if comes from untrusted client client. Fortunately we don't need it at all for generating URLs :) It will be in question when refactoring getClientIP() somewhen later.</span><br class="gmail-m_388361609629121005gmail-m_-525099954024514115gmail_msg"></div><div class="gmail-m_388361609629121005gmail-m_-525099954024514115gmail_msg"><span style="color:rgb(33,33,33)" class="gmail-m_388361609629121005gmail-m_-525099954024514115gmail_msg"><br></span></div><div class="gmail-m_388361609629121005gmail-m_-525099954024514115gmail_msg"><span style="color:rgb(33,33,33)" class="gmail-m_388361609629121005gmail-m_-525099954024514115gmail_msg">But can we trust </span><span style="color:rgb(33,33,33)" class="gmail-m_388361609629121005gmail-m_-525099954024514115gmail_msg">X-Forwarded-Host & X-Forwarded-Proto? From the first glance it isn't a problem since we are using them to display URLs for the same client, so nasty client will get his nasty URLs, that's it. But if app is doing something like storing URL in DB or (more likely) sending an email with a link to another client, this would be an issue.</span></div></div></div></blockquote><div><br></div><div>It's not safe to enable support for X-Forwarded-For and friends by default, since you can't know how application code will use that information and in many configurations it may be spoofed by clients.<br><br>A proper deployment which sets these headers looks like this:<br><br></div><div>1. Configure your frontend reverse-proxy (nginx or whatever) to discard incoming X-Forwarded-* headers and <i>set</i> X-Forwarded-* as appropriate. Note that X-Forwarded-For is actually a <i>list</i> of hops[1], so if you do this naively your server may append to the list! [2]<br></div><div>2. Configure your backend services to respect exactly the headers passed by your frontend.<br></div><div><br></div><div>Note that this requires administrative action in two places, and that if you don't do the frontend config it will probably pass the headers through, allowing them to be spoofed.<br></div><div><br></div><div>A non-exhaustive list of possible bad stuff I client could use spoofing for:<br><br></div><div>1. Evade IP-based access control (a reasonable defense-in-depth measure).<br></div><div>2. Evade pinning of user sessions to IP addresses or subnets.<br></div><div>2. Evade IP-based rate limiting, e.g. as discussed at [3].<br><br></div><div>It's also probably worth noting that Django used to offer support for X-Forwarded-For and removed it[4].  X-Forwarded-* and friends just too varied in the wild to reasonably support.<br><br></div><div>If Twisted is to support this in any way, I think that it should be opt-in support for the Forwarded header as specified in RFC 7239. This should be a parameter applicable to all of twisted.web.server rather than per-method call, since it's something the administrator needs to set.<br></div><div><br></div><div>—Tom<br></div><div><br>[1]: Standardized as Forwarded in <a href="https://tools.ietf.org/html/rfc7239" target="_blank">https://tools.ietf.org/html/<wbr>rfc7239</a><br></div><div>[2]: Your frontend proxy should also validate Host is a domain you control to prevent cookie theft. Plus lots of other stuff. Web security is hard, and every default everywhere sets users up for failure.<br>[3]: <a href="http://django-ratelimit.readthedocs.io/en/v1.0.0/security.html" target="_blank">http://django-ratelimit.<wbr>readthedocs.io/en/v1.0.0/<wbr>security.html</a><br>[4]: <a href="https://www.djangoproject.com/weblog/2009/jul/28/security/#secondary-issue" target="_blank">https://www.djangoproject.com/<wbr>weblog/2009/jul/28/security/#<wbr>secondary-issue</a></div></div></div></div>