]> git.parisson.com Git - django-social-auth.git/commitdiff
Fixed security hole - redirects via the next param are now properly sanitized to...
authorDarian Moody <mail@djm.org.uk>
Sun, 6 Mar 2011 02:39:37 +0000 (02:39 +0000)
committerDarian Moody <mail@djm.org.uk>
Sun, 6 Mar 2011 02:39:37 +0000 (02:39 +0000)
social_auth/utils.py [new file with mode: 0644]
social_auth/views.py

diff --git a/social_auth/utils.py b/social_auth/utils.py
new file mode 100644 (file)
index 0000000..1c8744d
--- /dev/null
@@ -0,0 +1,18 @@
+import urlparse
+
+def sanitize_redirect(host, redirect_to):
+    """
+    Given the hostname and an untrusted URL to redirect to,
+    this method tests it to make sure it isn't garbage/harmful
+    and returns it, else returns None.
+
+    See http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/views.py#L36
+    """
+    # Quick sanity check.
+    if not redirect_to:
+        return None
+    netloc = urlparse.urlparse(redirect_to)[1]
+    # Heavier security check -- don't allow redirection to a different host.
+    if netloc and netloc != host:
+        return None
+    return redirect_to
index b83095cf57944cba9d87957c94f9a3542101290d..cfe29c368dd22a42678594164e7e5738bd189f82 100644 (file)
@@ -1,21 +1,23 @@
 """Views"""
 from django.conf import settings
-from django.http import HttpResponseRedirect, HttpResponse, \
-                        HttpResponseServerError
+from django.http import HttpResponseRedirect, HttpResponse, HttpResponseServerError
 from django.core.urlresolvers import reverse
 from django.db import transaction
 from django.contrib.auth import login, REDIRECT_FIELD_NAME
 from django.contrib.auth.decorators import login_required
 
 from social_auth.backends import get_backend
+from social_auth.utils import sanitize_redirect
+
+
+DEFAULT_REDIRECT = getattr(settings, 'LOGIN_REDIRECT_URL', '')
 
 
 def auth(request, backend):
     """Start authentication process"""
     complete_url = getattr(settings, 'SOCIAL_AUTH_COMPLETE_URL_NAME',
                            'complete')
-    redirect = getattr(settings, 'LOGIN_REDIRECT_URL', '')
-    return auth_process(request, backend, complete_url, redirect)
+    return auth_process(request, backend, complete_url)
 
 
 @transaction.commit_on_success
@@ -47,8 +49,7 @@ def complete_process(request, backend):
             social_user = user.social_auth.get(provider=backend_name)
             if social_user.expiration_delta():
                 request.session.set_expiry(social_user.expiration_delta())
-        url = request.session.pop(REDIRECT_FIELD_NAME, '') or \
-              getattr(settings, 'LOGIN_REDIRECT_URL', '')
+        url = request.session.pop(REDIRECT_FIELD_NAME, '') or DEFAULT_REDIRECT
     else:
         url = getattr(settings, 'LOGIN_ERROR_URL', settings.LOGIN_URL)
     return HttpResponseRedirect(url)
@@ -59,8 +60,7 @@ def associate(request, backend):
     """Authentication starting process"""
     complete_url = getattr(settings, 'SOCIAL_AUTH_ASSOCIATE_URL_NAME',
                            'associate_complete')
-    redirect = getattr(settings, 'LOGIN_REDIRECT_URL', '')
-    return auth_process(request, backend, complete_url, redirect)
+    return auth_process(request, backend, complete_url)
 
 
 @login_required
@@ -70,8 +70,7 @@ def associate_complete(request, backend):
     if not backend:
         return HttpResponseServerError('Incorrect authentication service')
     backend.auth_complete(user=request.user)
-    url = request.session.pop(REDIRECT_FIELD_NAME, '') or \
-          getattr(settings, 'LOGIN_REDIRECT_URL', '')
+    url = request.session.pop(REDIRECT_FIELD_NAME, '') or DEFAULT_REDIRECT
     return HttpResponseRedirect(url)
 
 
@@ -82,20 +81,21 @@ def disconnect(request, backend):
     if not backend:
         return HttpResponseServerError('Incorrect authentication service')
     backend.disconnect(request.user)
-    url = request.REQUEST.get(REDIRECT_FIELD_NAME, '') or \
-          getattr(settings, 'LOGIN_REDIRECT_URL', '')
+    url = request.REQUEST.get(REDIRECT_FIELD_NAME, '') or DEFAULT_REDIRECT
     return HttpResponseRedirect(url)
 
 
-def auth_process(request, backend, complete_url_name, default_final_url):
+def auth_process(request, backend, complete_url_name, 
+                 default_redirect=DEFAULT_REDIRECT):
     """Authenticate using social backend"""
     redirect = reverse(complete_url_name, args=(backend,))
     backend = get_backend(backend, request, redirect)
     if not backend:
         return HttpResponseServerError('Incorrect authentication service')
     data = request.REQUEST
-    request.session[REDIRECT_FIELD_NAME] = data.get(REDIRECT_FIELD_NAME,
-                                                    default_final_url)
+    # Check and sanitize a user-defined GET/POST redirect_to field value.
+    redirect = sanitize_redirect(request.get_host(), data.get(REDIRECT_FIELD_NAME))
+    request.session[REDIRECT_FIELD_NAME] = redirect or DEFAULT_REDIRECT
     if backend.uses_redirect:
         return HttpResponseRedirect(backend.auth_url())
     else: