[Python-modules-commits] r15619 - in packages/python-django/branches/squeeze/debian (6 files)

hertzog at users.alioth.debian.org hertzog at users.alioth.debian.org
Sat Feb 12 08:59:04 UTC 2011


    Date: Saturday, February 12, 2011 @ 08:59:02
  Author: hertzog
Revision: 15619

* Stable security upload:
  http://www.djangoproject.com/weblog/2011/feb/08/security/
* Apply/backport the 3 security patches:
  - debian/patches/10_fix_csrf_ajax.diff
  - debian/patches/11_fix_admin_file_widget.diff
  - debian/patches/12_fix_file_session_backend.diff
* Re-add dropped test for 09_fix_dos_password_reset.diff. Thanks to
  Jamie Strandboge <jamie at ubuntu.com>. Closes: #610447

Added:
  packages/python-django/branches/squeeze/debian/patches/10_fix_csrf_ajax.diff
  packages/python-django/branches/squeeze/debian/patches/11_fix_admin_file_widget.diff
  packages/python-django/branches/squeeze/debian/patches/12_fix_file_session_backend.diff
Modified:
  packages/python-django/branches/squeeze/debian/changelog
  packages/python-django/branches/squeeze/debian/patches/09_fix_dos_password_reset.diff
  packages/python-django/branches/squeeze/debian/patches/series

Modified: packages/python-django/branches/squeeze/debian/changelog
===================================================================
--- packages/python-django/branches/squeeze/debian/changelog	2011-02-12 08:52:46 UTC (rev 15618)
+++ packages/python-django/branches/squeeze/debian/changelog	2011-02-12 08:59:02 UTC (rev 15619)
@@ -1,3 +1,16 @@
+python-django (1.2.3-4) stable-security; urgency=low
+
+  * Stable security upload:
+    http://www.djangoproject.com/weblog/2011/feb/08/security/
+  * Apply/backport the 3 security patches:
+    - debian/patches/10_fix_csrf_ajax.diff
+    - debian/patches/11_fix_admin_file_widget.diff
+    - debian/patches/12_fix_file_session_backend.diff
+  * Re-add dropped test for 09_fix_dos_password_reset.diff. Thanks to
+    Jamie Strandboge <jamie at ubuntu.com>. Closes: #610447
+
+ -- Raphaël Hertzog <hertzog at debian.org>  Sat, 12 Feb 2011 09:17:26 +0100
+
 python-django (1.2.3-3) testing; urgency=high
 
   * Squeeze upload with security fixes only:

Modified: packages/python-django/branches/squeeze/debian/patches/09_fix_dos_password_reset.diff
===================================================================
--- packages/python-django/branches/squeeze/debian/patches/09_fix_dos_password_reset.diff	2011-02-12 08:52:46 UTC (rev 15618)
+++ packages/python-django/branches/squeeze/debian/patches/09_fix_dos_password_reset.diff	2011-02-12 08:59:02 UTC (rev 15619)
@@ -1,7 +1,6 @@
-Description: Fix denial-of-service attack in password-reset mechanism
- http://www.djangoproject.com/weblog/2010/dec/22/security/
-Origin: upstream, http://code.djangoproject.com/changeset/15034
-
+Description: Fix denial-of-service attack in password-reset mechanism
+Origin: upstream, http://code.djangoproject.com/changeset/15034
+Bug: http://www.djangoproject.com/weblog/2010/dec/22/security/
 --- a/django/contrib/auth/urls.py
 +++ b/django/contrib/auth/urls.py
 @@ -1,4 +1,4 @@
@@ -36,3 +35,15 @@
      return int(s, 36)
  
  def int_to_base36(i):
+--- a/django/contrib/auth/tests/tokens.py	2011-01-18 08:57:34.000000000 -0600
++++ b/django/contrib/auth/tests/tokens.py	2011-01-18 08:57:40.000000000 -0600
+@@ -34,4 +34,9 @@
+ >>> p2.check_token(u, tk1)
+ False
+ 
++This will put a 14-digit base36 timestamp into the token, which is too large.
++>>> tk1 = p0._make_token_with_timestamp(u, 175455491841851871349)
++>>> p0.check_token(u, tk1)
++False
++
+ """

Added: packages/python-django/branches/squeeze/debian/patches/10_fix_csrf_ajax.diff
===================================================================
--- packages/python-django/branches/squeeze/debian/patches/10_fix_csrf_ajax.diff	                        (rev 0)
+++ packages/python-django/branches/squeeze/debian/patches/10_fix_csrf_ajax.diff	2011-02-12 08:59:02 UTC (rev 15619)
@@ -0,0 +1,163 @@
+Description: Fix flaw in CSRF handling
+Origin: backport, http://code.djangoproject.com/changeset/15465
+Bug: http://www.djangoproject.com/weblog/2011/feb/08/security/
+
+--- a/django/middleware/csrf.py
++++ b/django/middleware/csrf.py
+@@ -85,6 +85,7 @@ class CsrfViewMiddleware(object):
+     tag.
+     """
+     def process_view(self, request, callback, callback_args, callback_kwargs):
++
+         if getattr(request, 'csrf_processing_done', False):
+             return None
+ 
+@@ -126,31 +127,6 @@ class CsrfViewMiddleware(object):
+                 # any branches that call reject()
+                 return accept()
+ 
+-            if request.is_ajax():
+-                # .is_ajax() is based on the presence of X-Requested-With.  In
+-                # the context of a browser, this can only be sent if using
+-                # XmlHttpRequest.  Browsers implement careful policies for
+-                # XmlHttpRequest:
+-                #
+-                #  * Normally, only same-domain requests are allowed.
+-                #
+-                #  * Some browsers (e.g. Firefox 3.5 and later) relax this
+-                #    carefully:
+-                #
+-                #    * if it is a 'simple' GET or POST request (which can
+-                #      include no custom headers), it is allowed to be cross
+-                #      domain.  These requests will not be recognized as AJAX.
+-                #
+-                #    * if a 'preflight' check with the server confirms that the
+-                #      server is expecting and allows the request, cross domain
+-                #      requests even with custom headers are allowed. These
+-                #      requests will be recognized as AJAX, but can only get
+-                #      through when the developer has specifically opted in to
+-                #      allowing the cross-domain POST request.
+-                #
+-                # So in all cases, it is safe to allow these requests through.
+-                return accept()
+-
+             if request.is_secure():
+                 # Strict referer checking for HTTPS
+                 referer = request.META.get('HTTP_REFERER')
+@@ -181,7 +157,11 @@ class CsrfViewMiddleware(object):
+                 csrf_token = request.META["CSRF_COOKIE"]
+ 
+             # check incoming token
+-            request_csrf_token = request.POST.get('csrfmiddlewaretoken', None)
++            request_csrf_token = request.POST.get('csrfmiddlewaretoken', "")
++            if request_csrf_token == "":
++                # Fall back to X-CSRFToken, to make things easier for AJAX
++                request_csrf_token = request.META.get('HTTP_X_CSRFTOKEN', '')
++
+             if request_csrf_token != csrf_token:
+                 if cookie_is_new:
+                     # probably a problem setting the CSRF cookie
+--- a/tests/regressiontests/csrf_tests/tests.py
++++ b/tests/regressiontests/csrf_tests/tests.py
+@@ -275,12 +275,12 @@ class CsrfMiddlewareTest(TestCase):
+         req2 = CsrfMiddleware().process_view(req, csrf_exempt(post_form_view), (), {})
+         self.assertEquals(None, req2)
+ 
+-    def test_ajax_exemption(self):
++    def test_csrf_token_in_header(self):
+         """
+-        Check that AJAX requests are automatically exempted.
++        Check that we can pass in the token in a header instead of in the form
+         """
+         req = self._get_POST_csrf_cookie_request()
+-        req.META['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
++        req.META['HTTP_X_CSRFTOKEN'] = self._csrf_id
+         req2 = CsrfMiddleware().process_view(req, post_form_view, (), {})
+         self.assertEquals(None, req2)
+ 
+--- a/docs/ref/contrib/csrf.txt
++++ b/docs/ref/contrib/csrf.txt
+@@ -81,6 +81,47 @@ The utility script ``extras/csrf_migrati
+ finding of code and templates that may need to be upgraded.  It contains full
+ help on how to use it.
+ 
++AJAX
++----
++
++While the above method can be used for AJAX POST requests, it has some
++inconveniences: you have to remember to pass the CSRF token in as POST data with
++every POST request. For this reason, there is an alternative method: on each
++XMLHttpRequest, set a custom `X-CSRFToken` header to the value of the CSRF
++token. This is often easier, because many javascript frameworks provide hooks
++that allow headers to be set on every request. In jQuery, you can use the
++``beforeSend`` hook as follows:
++
++.. code-block:: javascript
++
++    $.ajaxSetup({
++        beforeSend: function(xhr, settings) {
++            function getCookie(name) {
++                var cookieValue = null;
++                if (document.cookie && document.cookie != '') {
++                    var cookies = document.cookie.split(';');
++                    for (var i = 0; i < cookies.length; i++) {
++                        var cookie = jQuery.trim(cookies[i]);
++                        // Does this cookie string begin with the name we want?
++                        if (cookie.substring(0, name.length + 1) == (name + '=')) {
++                            cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
++                            break;
++                        }
++                    }
++                }
++                return cookieValue;
++            }
++            if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
++                // Only send the token to relative URLs i.e. locally.
++                xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
++            }
++        }
++    });
++
++Adding this to a javascript file that is included on your site will ensure that
++AJAX POST requests that are made via jQuery will not be caught by the CSRF
++protection.
++
+ The decorator method
+ --------------------
+ 
+@@ -262,10 +303,6 @@ in the same module.  These disable the v
+ (``CsrfResponseMiddleware``) respectively.  They can be used individually if
+ required.
+ 
+-You don't have to worry about doing this for most AJAX views. Any request sent
+-with "X-Requested-With: XMLHttpRequest" is automatically exempt. (See the `How
+-it works`_ section.)
+-
+ Subdomains
+ ----------
+ 
+@@ -343,24 +380,6 @@ request ought to be harmless.
+ response, and only pages that are served as 'text/html' or
+ 'application/xml+xhtml' are modified.
+ 
+-AJAX
+-----
+-
+-The middleware tries to be smart about requests that come in via AJAX. Most
+-modern JavaScript toolkits send an "X-Requested-With: XMLHttpRequest" HTTP
+-header; these requests are detected and automatically *not* handled by this
+-middleware.  We can do this safely because, in the context of a browser, the
+-header can only be added by using ``XMLHttpRequest``, and browsers already
+-implement a same-domain policy for ``XMLHttpRequest``.
+-
+-For the more recent browsers that relax this same-domain policy, custom headers
+-like "X-Requested-With" are only allowed after the browser has done a
+-'preflight' check to the server to see if the cross-domain request is allowed,
+-using a strictly 'opt in' mechanism, so the exception for AJAX is still safe—if
+-the developer has specifically opted in to allowing cross-site AJAX POST
+-requests on a specific URL, they obviously don't want the middleware to disallow
+-exactly that.
+-
+ .. _9.1.1 Safe Methods, HTTP 1.1, RFC 2616: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
+ 
+ Caching

Added: packages/python-django/branches/squeeze/debian/patches/11_fix_admin_file_widget.diff
===================================================================
--- packages/python-django/branches/squeeze/debian/patches/11_fix_admin_file_widget.diff	                        (rev 0)
+++ packages/python-django/branches/squeeze/debian/patches/11_fix_admin_file_widget.diff	2011-02-12 08:59:02 UTC (rev 15619)
@@ -0,0 +1,37 @@
+Description: Fix potential XSS in file field rendering
+Origin: upstream, http://code.djangoproject.com/changeset/15472
+Bug: http://www.djangoproject.com/weblog/2011/feb/08/security/
+
+--- a/django/contrib/admin/widgets.py
++++ b/django/contrib/admin/widgets.py
+@@ -96,7 +96,7 @@ class AdminFileWidget(forms.FileInput):
+         output = []
+         if value and hasattr(value, "url"):
+             output.append('%s <a target="_blank" href="%s">%s</a> <br />%s ' % \
+-                (_('Currently:'), value.url, value, _('Change:')))
++                (_('Currently:'), escape(value.url), escape(value), _('Change:')))
+         output.append(super(AdminFileWidget, self).render(name, value, attrs))
+         return mark_safe(u''.join(output))
+ 
+--- a/tests/regressiontests/admin_widgets/tests.py
++++ b/tests/regressiontests/admin_widgets/tests.py
+@@ -151,3 +151,19 @@ class AdminForeignKeyRawIdWidget(DjangoT
+             post_data)
+         self.assertContains(response,
+             'Select a valid choice. That choice is not one of the available choices.')
++
++class AdminFileWidgetTest(DjangoTestCase):
++    def test_render_escapes_html(self):
++        class StrangeFieldFile(object):
++            url = "something?chapter=1&sect=2&copy=3&lang=en"
++
++            def __unicode__(self):
++                return u'''something<div onclick="alert('oops')">.jpg'''
++
++        widget = AdminFileWidget()
++        field = StrangeFieldFile()
++        output = widget.render('myfile', field)
++        self.assertFalse(field.url in output)
++        self.assertTrue(u'href="something?chapter=1&amp;sect=2&amp;copy=3&amp;lang=en"' in output)
++        self.assertFalse(unicode(field) in output)
++        self.assertTrue(u'something&lt;div onclick=&quot;alert(&#39;oops&#39;)&quot;&gt;.jpg' in output)

Added: packages/python-django/branches/squeeze/debian/patches/12_fix_file_session_backend.diff
===================================================================
--- packages/python-django/branches/squeeze/debian/patches/12_fix_file_session_backend.diff	                        (rev 0)
+++ packages/python-django/branches/squeeze/debian/patches/12_fix_file_session_backend.diff	2011-02-12 08:59:02 UTC (rev 15619)
@@ -0,0 +1,45 @@
+Description: Fix directory-traversal vulnerability on Windows
+Origin: upstream, http://code.djangoproject.com/changeset/15468
+Bug: http://www.djangoproject.com/weblog/2011/feb/08/security/
+
+Index: Django/django/contrib/sessions/tests.py
+===================================================================
+--- Django/django/contrib/sessions/tests.py	(revision 9934)
++++ Django/django/contrib/sessions/tests.py	(revision 15468)
+@@ -130,4 +130,15 @@
+ >>> file_session.save()
+ 
++# Ensure we don't allow directory traversal
++>>> FileSession("a/b/c").load()
++Traceback (innermost last):
++    ...
++SuspiciousOperation: Invalid characters in session key
++
++>>> FileSession("a\\b\\c").load()
++Traceback (innermost last):
++    ...
++SuspiciousOperation: Invalid characters in session key
++
+ # Make sure the file backend checks for a good storage dir
+ >>> settings.SESSION_FILE_PATH = "/if/this/directory/exists/you/have/a/weird/computer"
+Index: Django/django/contrib/sessions/backends/file.py
+===================================================================
+--- Django/django/contrib/sessions/backends/file.py	(revision 8812)
++++ Django/django/contrib/sessions/backends/file.py	(revision 15468)
+@@ -27,4 +27,6 @@
+         super(SessionStore, self).__init__(session_key)
+ 
++    VALID_KEY_CHARS = set("abcdef0123456789")
++
+     def _key_to_file(self, session_key=None):
+         """
+@@ -37,7 +39,7 @@
+         # should always be md5s, so they should never contain directory
+         # components.
+-        if os.path.sep in session_key:
++        if not set(session_key).issubset(self.VALID_KEY_CHARS):
+             raise SuspiciousOperation(
+-                "Invalid characters (directory components) in session key")
++                "Invalid characters in session key")
+ 
+         return os.path.join(self.storage_path, self.file_prefix + session_key)

Modified: packages/python-django/branches/squeeze/debian/patches/series
===================================================================
--- packages/python-django/branches/squeeze/debian/patches/series	2011-02-12 08:52:46 UTC (rev 15618)
+++ packages/python-django/branches/squeeze/debian/patches/series	2011-02-12 08:59:02 UTC (rev 15619)
@@ -6,3 +6,6 @@
 07_disable_url_verify_model_tests.diff
 08_fix_info_leakage.diff
 09_fix_dos_password_reset.diff
+10_fix_csrf_ajax.diff
+11_fix_admin_file_widget.diff
+12_fix_file_session_backend.diff




More information about the Python-modules-commits mailing list