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 >>>> >>>> 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 >>>>>>>>>>>>>> >>>>>>>>>>>>>> >>>>>>>>>>>>>> >>>>>>>>>>>>>>
--