Yes exactly

On Thursday, October 4, 2012 12:38:34 PM UTC-4, Massimo Di Pierro wrote:
>
> So... would replaing this in gluon.main.py 
>
> is_https = env.wsgi_url_scheme in ['https', 'HTTPS'] or env.https=='on')
>
> with 
>
> is_https = env.wsgi_url_scheme in ['https', 'HTTPS'] or env.https=='on' or 
> request.env.http_x_forwarded_proto in ['https', 'HTTPS']
>
> address the first issue?
>
> Massimo
>
> On Thursday, 4 October 2012 07:05:17 UTC-5, Yarin wrote:
>>
>> I'm revising my stance on this. After further digging around, I'm gonna 
>> go with Niphlod's position that securing only the login traffic without 
>> securing the entire session is for the most part pretty worthless. While 
>> this might have value to some sites that have to deal with mixed content, 
>> the complexity it introduces isn't worth it.
>>
>> I'm also taking back my recommendation that we need to have a setting to 
>> explicitly allow SSL traffic. I think it's fine to just check the headers 
>> for forwarded SSL traffic and trust that it is. Yes, headers can be 
>> spoofed, but I can't think of how this could be exploited on the user end- 
>>
>> So that leaves only *two recommended changes:*
>>
>>    - When checking whether HTTPS, check for forwarded SSL headers with if
>>     request.env.http_x_forwarded_proto in ['https', 'HTTPS']:
>>    - Add a auth.secure = True convenience setting, which would call 
>>    requires_https() while the user is logged in, and on all 
>> login/registration 
>>    methods.
>>    
>> I'll update the ticket
>>
>>
>>
>> On Friday, September 21, 2012 2:26:36 PM UTC-4, Yarin wrote:
>>>
>>> Done http://code.google.com/p/web2py/issues/detail?id=1023
>>>
>>> On Friday, September 21, 2012 2:05:41 PM UTC-4, Massimo Di Pierro wrote:
>>>>
>>>> Yarin, please open an issue on google code as suggested enhancement so 
>>>> ti does not get lost. Also feel free to move the discussion on web2py 
>>>> developers.
>>>>
>>>>
>>>> On Friday, 21 September 2012 12:22:57 UTC-5, Yarin wrote:
>>>>>
>>>>> Here's a complete example of our own implementation (simplified, 
>>>>> untested) using the proposed auth settings:
>>>>>
>>>>> *In our model:*
>>>>>
>>>>> def force_https(trust_proxy = False, secure_session = False):
>>>>>     """ Enforces HTTPS in appropriate environments
>>>>>
>>>>>     Args:
>>>>>         trust_proxy: Can we trust proxy header 
>>>>> 'http_x_forwarded_proto' to determine SSL.
>>>>>         (Set this only if ALL your traffic comes via trusted proxy.)
>>>>>         secure_session: Secure the session as well. 
>>>>>         (Do this only when enforcing SSL throughout the session)
>>>>>     """
>>>>>
>>>>>     # If cronjob or scheduler, exit:
>>>>>     cronjob = request.global_settings.cronjob
>>>>>     cmd_options = request.global_settings.cmd_options
>>>>>     if cronjob or (cmd_options and cmd_options.scheduler):
>>>>>         return
>>>>>
>>>>>     # If local host, exit:
>>>>>     if request.env.remote_addr == "127.0.0.1":
>>>>>         return
>>>>>
>>>>>     # If already HTTPS, exit:
>>>>>     if request.env.wsgi_url_scheme in ['https', 'HTTPS']:
>>>>>         if secure_session:
>>>>>             current.session.secure()
>>>>>         return
>>>>>
>>>>>     # If HTTPS request forwarded over HTTP via a SSL-terminating 
>>>>> proxy, exit:
>>>>>     if trust_proxy and request.env.http_x_forwarded_proto in ['https', 
>>>>> 'HTTPS']: 
>>>>>         if secure_session:
>>>>>             current.session.secure()
>>>>>         return
>>>>>
>>>>>     # Redirect to HTTPS:
>>>>>     redirect(URL(scheme='https', args=request.args, vars=request.vars
>>>>> ))
>>>>>
>>>>> # If a login function, force SSL:
>>>>> if request.controller == 'default' and request.function == 'user' andauth
>>>>> .settings.force_ssl_login:
>>>>>     force_https(trust_proxy = auth.settings.is_proxied, secure_session 
>>>>> = auth.settings.force_ssl_session)
>>>>> # If user is logged in and we're enforcing a full SSL session:
>>>>> elif auth.is_logged_in() and auth.settings.force_ssl_session:
>>>>>     force_https(trust_proxy = auth.settings.is_proxied,secure_session 
>>>>> = True)
>>>>>
>>>>> def on_login(form):
>>>>>     """ Post login redirection"""
>>>>>
>>>>>     # If we're enforcing SSL on login only, redirect from HTTPS to 
>>>>> HTTP immediately after login:
>>>>>     if auth.settings.force_ssl_login is True and 
>>>>> auth.settings.force_ssl_session 
>>>>> is False:
>>>>>         if request.env.wsgi_url_scheme in ['https', 'HTTPS'] orrequest
>>>>> .env.http_x_forwarded_proto in ['https', 'HTTPS']:
>>>>>
>>>>>             # Extract the post-login url value from auth 
>>>>>             # (hack - look at end of login() function in tools.py. 
>>>>> This belongs in Auth itself.):
>>>>>             login_next_path = auth.next or auth.settings.login_next
>>>>>             # Build an absolute, HTTP url from it:
>>>>>             login_next_url = URL(scheme='http',c='default',f='index') 
>>>>> + login_next_path[1:]
>>>>>             # Redirect to the HTTP URL:
>>>>>             redirect(login_next_url)
>>>>>
>>>>> auth.settings.login_onaccept = on_login
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> On Friday, September 21, 2012 12:35:37 PM UTC-4, Yarin wrote:
>>>>>>
>>>>>> You can't detect this- it must be a setting. Please see my previous 
>>>>>> answer:
>>>>>> https://groups.google.com/forum/#!msg/web2py/me1e5d6Dudk/VQRQhdiryccJ
>>>>>>
>>>>>> "you cannot detect whether proxied traffic is real because headers 
>>>>>> are unreliable. Instead you must securely set up a server behind a proxy 
>>>>>> and set the .is_proxied flag explicitly."
>>>>>>
>>>>>> "you can't mix direct and proxied traffic. To be able to handle 
>>>>>> proxy-terminated SSL, we need to know that *all* the traffic is via 
>>>>>> a trusted proxy."
>>>>>>
>>>>>>
>>>>>> On Friday, September 21, 2012 12:05:56 PM UTC-4, Massimo Di Pierro 
>>>>>> wrote:
>>>>>>>
>>>>>>> Yes but how do you detect if is_proxied reliably?
>>>>>>>
>>>>>>> On Friday, 21 September 2012 10:28:26 UTC-5, Yarin wrote:
>>>>>>>>
>>>>>>>> FYI this is the enforcer function we wrote for our implementation- 
>>>>>>>> basically a rewrite of request.requires_https():
>>>>>>>>
>>>>>>>> def force_https(trust_proxy = False):
>>>>>>>>  """ Enforces HTTPS in appropriate environments
>>>>>>>>  
>>>>>>>>  Args:
>>>>>>>>      trust_proxy: Can we trust proxy header 
>>>>>>>> 'http_x_forwarded_proto' to determine SSL.
>>>>>>>>      (Set this only if ALL your traffic comes via trusted proxy.)
>>>>>>>>  """
>>>>>>>>  
>>>>>>>>  # If cronjob or scheduler, exit:
>>>>>>>>  cronjob = request.global_settings.cronjob
>>>>>>>>  cmd_options = request.global_settings.cmd_options
>>>>>>>>  if cronjob or (cmd_options and cmd_options.scheduler):
>>>>>>>>      return
>>>>>>>>
>>>>>>>>  # If local host, exit:
>>>>>>>>  if request.env.remote_addr == "127.0.0.1":
>>>>>>>>      return
>>>>>>>>  
>>>>>>>>  # If already HTTPS, exit:
>>>>>>>>  if request.env.wsgi_url_scheme in ['https', 'HTTPS']:
>>>>>>>>      return
>>>>>>>>  
>>>>>>>>  # If HTTPS request forwarded over HTTP via SSL-terminating proxy, 
>>>>>>>> exit:
>>>>>>>>  if trust_proxy and request.env.http_x_forwarded_proto in ['https', 
>>>>>>>> 'HTTPS']: 
>>>>>>>>      return
>>>>>>>>  
>>>>>>>>  # Redirect to HTTPS:
>>>>>>>>  redirect(URL(scheme='https', args=request.args, vars=request.vars
>>>>>>>> ))
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> On Friday, September 21, 2012 9:53:36 AM UTC-4, Yarin wrote:
>>>>>>>>>
>>>>>>>>> The completely naive approach would be to do: 
>>>>>>>>>
>>>>>>>>> if request.env.http_x_forwarded_for and \
>>>>>>>>>     request.env.http_x_forwarded_proto in ['https', 'HTTPS']:
>>>>>>>>>      # Is HTTPS...
>>>>>>>>>
>>>>>>>>> But you cannot detect whether proxied traffic is real because 
>>>>>>>>> headers are unreliable. Instead it is up to the user to securely set 
>>>>>>>>> up a 
>>>>>>>>> server behind a proxy and set the .is_proxied flag themselves.
>>>>>>>>>
>>>>>>>>> *Example:*
>>>>>>>>> We put our app server behind an SSL-terminating load balancer on 
>>>>>>>>> the cloud. The domain app.example.com points to the loadbalancer, 
>>>>>>>>> so we configure app server's Apache to allow traffic from that domain 
>>>>>>>>> only, 
>>>>>>>>> and block any outside direct traffic. Then we set *
>>>>>>>>> auth.settings.is_proxied* to tell web2py "this proxy traffic is 
>>>>>>>>> legit"
>>>>>>>>>
>>>>>>>>> HTTPS/443 requests will hit the loadbalancer, and be transformed 
>>>>>>>>> to HTTP/80 traffic with *http_x_forwarded_for* and *
>>>>>>>>> http_x_forwarded_proto* headers set. Now we can confidently check:
>>>>>>>>>
>>>>>>>>> if auth.settings.is_proxied and \
>>>>>>>>>     request.env.http_x_forwarded_proto in ['https', 'HTTPS']:
>>>>>>>>>     # Is HTTPS...
>>>>>>>>>
>>>>>>>>> In other words *http_x_forwarded_for* header is useless and you 
>>>>>>>>> can't mix direct and proxied traffic. To be able to handle 
>>>>>>>>> proxy-terminated 
>>>>>>>>> SSL, we need to know that *all* the traffic is via a trusted 
>>>>>>>>> proxy.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On Friday, September 21, 2012 8:40:35 AM UTC-4, Massimo Di Pierro 
>>>>>>>>> wrote:
>>>>>>>>>>
>>>>>>>>>> Can you suggest a way to detect that?
>>>>>>>>>>
>>>>>>>>>> On Thursday, 20 September 2012 13:56:55 UTC-5, Yarin wrote:
>>>>>>>>>>>
>>>>>>>>>>> @Massimo - that'd be great. 
>>>>>>>>>>>
>>>>>>>>>>> One more kink to throw in is recognizing proxied SSL calls. This 
>>>>>>>>>>> requires knowing whether you can trust the traffic headers (e.g. 
>>>>>>>>>>> having 
>>>>>>>>>>> apache locked down to all traffic except your load balancer), so 
>>>>>>>>>>> maybe we 
>>>>>>>>>>> need a trust_proxied_ssl or is_proxied setting somewhere?
>>>>>>>>>>>
>>>>>>>>>>> if request.env.http_x_forwarded_for and 
>>>>>>>>>>> request.env.http_x_forwarded_proto 
>>>>>>>>>>> in ['https', 'HTTPS'] and auth.settings.is_proxied:
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> On Thursday, September 20, 2012 12:52:22 PM UTC-4, Massimo Di 
>>>>>>>>>>> Pierro wrote:
>>>>>>>>>>>>
>>>>>>>>>>>> I think we should do something like this. 
>>>>>>>>>>>>
>>>>>>>>>>>> I think we should have auth.settings.force_ssl_login 
>>>>>>>>>>>> and  auth.settings.force_ssl_login.
>>>>>>>>>>>> We could add secure=True option to existing requires validators.
>>>>>>>>>>>>
>>>>>>>>>>>> This should not be enforced from localhost.
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> On Thursday, 20 September 2012 09:07:14 UTC-5, Yarin wrote:
>>>>>>>>>>>>>
>>>>>>>>>>>>> A proposal for improving SSL support in web2py 
>>>>>>>>>>>>>
>>>>>>>>>>>>> For authenticated web applications, there are two "grades" of 
>>>>>>>>>>>>> SSL implementions: Forcing SSL on login, vs forcing SSL on the 
>>>>>>>>>>>>> entire 
>>>>>>>>>>>>> authenticated session.
>>>>>>>>>>>>>
>>>>>>>>>>>>> In the first case, HTTPS is forced on login/registration, but 
>>>>>>>>>>>>> reverts back to HTTP upon authentication. This protects against 
>>>>>>>>>>>>> passwords 
>>>>>>>>>>>>> from being sent unencrypted, but won't prevent session hijacking 
>>>>>>>>>>>>> as the 
>>>>>>>>>>>>> session cookie can still be compromised on subsequent HTTP 
>>>>>>>>>>>>> requests. (See 
>>>>>>>>>>>>> Firesheep <http://codebutler.com/firesheep> for details). 
>>>>>>>>>>>>> Nonetheless, many sites choose this approach for performance 
>>>>>>>>>>>>> reasons, as 
>>>>>>>>>>>>> SSL-delivered content is not cached by browsers as efficiently 
>>>>>>>>>>>>> (discussed 
>>>>>>>>>>>>> on 37signals 
>>>>>>>>>>>>> blog<http://37signals.com/svn/posts/1431-mixed-content-warning-how-i-loathe-thee>
>>>>>>>>>>>>> ).
>>>>>>>>>>>>>
>>>>>>>>>>>>> In the second case, the entire authenticated session is 
>>>>>>>>>>>>> secured by forcing all traffic to go over HTTPS while a user is 
>>>>>>>>>>>>> logged in 
>>>>>>>>>>>>> *and* by securing the session cookie so that it will only be 
>>>>>>>>>>>>> sent by the browser over HTTPS.
>>>>>>>>>>>>>
>>>>>>>>>>>>> (Also discussed in web2py users group - Auth over 
>>>>>>>>>>>>> SSL<https://groups.google.com/d/msg/web2py/7qoHMs-4Va8/jRFOqYHri4gJ>
>>>>>>>>>>>>> )
>>>>>>>>>>>>>
>>>>>>>>>>>>> web2py should make it easier to deal with these scenarios. I 
>>>>>>>>>>>>> just implemented a case-1 type solution and it took quite a bit 
>>>>>>>>>>>>> of work.
>>>>>>>>>>>>>
>>>>>>>>>>>>> Moreover, web2py currently provides two SSL-control functions, 
>>>>>>>>>>>>> which, taken on their own, can lead to problems for the 
>>>>>>>>>>>>> uninitiated:
>>>>>>>>>>>>>
>>>>>>>>>>>>>    - session.secure() will ensure that the session cookie is 
>>>>>>>>>>>>>    only transmitted over HTTPS, but doesn't force HTTPS, so that 
>>>>>>>>>>>>> for any 
>>>>>>>>>>>>>    subsequent session calls made over HTTP will simply not have 
>>>>>>>>>>>>> access to the 
>>>>>>>>>>>>>    auth session, but this is not obvious (Correct me if I'm wrong)
>>>>>>>>>>>>>    - request.requires_https() (undocumented?) is a misnomer, 
>>>>>>>>>>>>>    because if forces HTTPS but then assumes a case-2 scenario 
>>>>>>>>>>>>>    and secures the session cookie
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> *Proposals:*
>>>>>>>>>>>>>
>>>>>>>>>>>>>    - SSL auth settings
>>>>>>>>>>>>>       - auth.settings.force_ssl_login - Forces HTTPS for 
>>>>>>>>>>>>>       login/registration
>>>>>>>>>>>>>       - auth.settings.force_ssl_session - Forces HTTPS 
>>>>>>>>>>>>>       throughout an authenticated session, and secure the session 
>>>>>>>>>>>>> cookie (If 
>>>>>>>>>>>>>       True, force_ssl_login not necessary)
>>>>>>>>>>>>>    - Other more granular controls
>>>>>>>>>>>>>       - @requires_https() - decorator for controller 
>>>>>>>>>>>>>       functions that forces HTTPS for that function only
>>>>>>>>>>>>>       - 'secure=True' option on forms ensures submission over 
>>>>>>>>>>>>>       HTTPS
>>>>>>>>>>>>>    
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>>

-- 



Reply via email to