changeset 68:1e144e9c1847

Sanitize the 'next' parameter of the login form before redirecting.
author Daniele Nicolodi <daniele@grinta.net>
date Sun, 14 Aug 2011 19:31:28 +0200
parents ad6e52b8d07c
children d799c05caaad
files src/ltpdarepo/__init__.py src/ltpdarepo/security.py
diffstat 2 files changed, 13 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/src/ltpdarepo/__init__.py	Sun Aug 14 19:31:28 2011 +0200
+++ b/src/ltpdarepo/__init__.py	Sun Aug 14 19:31:28 2011 +0200
@@ -1,4 +1,4 @@
-from urlparse import urljoin
+from urlparse import urlparse, urljoin
 from flask import Flask, g, request, session, render_template, Markup, redirect, flash, url_for
 from pkg_resources import get_distribution
 import MySQLdb as mysql
@@ -85,13 +85,21 @@
 app.jinja_env.globals['url_for_other_order'] = url_for_other_order
 
 
+def is_safe_url(target):
+    ref = urlparse(request.host_url)
+    test = urlparse(urljoin(request.host_url, target))
+    return test.scheme in ('http', 'https') and test.netloc == ref.netloc
+
+
 @app.route('/login', methods=['GET', 'POST'])
 def login():
     if request.method == 'POST':
         if authenticate(request.form['username'], request.form['password']):
             session['username'] = request.form['username']
-            url = urljoin(url_for('.index'), request.args.get('next', ''))
-            return redirect(url)
+            target = request.args.get('next')
+            if not target or not is_safe_url(target):
+                target = url_for('index')
+            return redirect(target)
         flash('Login failed.', category='error')
 
     return render_template('login.html')
--- a/src/ltpdarepo/security.py	Sun Aug 14 19:31:28 2011 +0200
+++ b/src/ltpdarepo/security.py	Sun Aug 14 19:31:28 2011 +0200
@@ -58,10 +58,8 @@
         @wraps(func)
         def decorated(*args, **kwargs):
             if 'username' not in session:
-                url = request.path
-                if url == '/':
-                    url = None
-                return redirect(url_for('login', next=url))
+                target = request.path != '/' and request.path or None
+                return redirect(url_for('login', next=target))
             if self.role not in g.identity.roles:
                 abort(403)
             return func(*args, **kwargs)