Awesome thanks Massimo- will test tonight On Thu, Oct 4, 2012 at 4:13 PM, Massimo Di Pierro < massimo.dipie...@gmail.com> wrote:
> OK. check trunk. Auth(db,secure=True). > > > On Thursday, 4 October 2012 13:01:51 UTC-5, Yarin wrote: >> >> 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<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.cronjo**b >>>>>>> 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' >>>>>>> and auth.settings.force_ssl_login: >>>>>>> force_https(trust_proxy = auth.settings.is_proxied, secu**re_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<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 an**d 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 >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> -- > > > > --