You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by jo...@apache.org on 2013/08/26 19:06:01 UTC
git commit: [#6604] escape < to \u003C in JSON to ensure it cannot be
parsed as HTML and be subject to XSS
Updated Branches:
refs/heads/master e42b20b37 -> 1843655af
[#6604] escape < to \u003C in JSON to ensure it cannot be parsed as HTML and be subject to XSS
Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/1843655a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/1843655a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/1843655a
Branch: refs/heads/master
Commit: 1843655afd93053119ad454a6628083c0e06284d
Parents: e42b20b
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Mon Aug 26 16:35:51 2013 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Mon Aug 26 16:53:30 2013 +0000
----------------------------------------------------------------------
Allura/allura/lib/patches.py | 23 ++++++++++++++++++++
.../forgewiki/tests/functional/test_rest.py | 21 +++++++++++++++++-
2 files changed, 43 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/1843655a/Allura/allura/lib/patches.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/patches.py b/Allura/allura/lib/patches.py
index 60c4648..804c947 100644
--- a/Allura/allura/lib/patches.py
+++ b/Allura/allura/lib/patches.py
@@ -15,10 +15,14 @@
# specific language governing permissions and limitations
# under the License.
+import re
+
import webob
import tg.decorators
from decorator import decorator
from pylons import request
+import mock
+import simplejson
from allura.lib import helpers as h
@@ -78,6 +82,25 @@ def apply():
return func(*args, **kwargs)
+ # http://blog.watchfire.com/wfblog/2011/10/json-based-xss-exploitation.html
+ # change < to its unicode escape when rendering JSON out of turbogears
+ # This is to avoid IE9 and earlier, which don't know the json content type
+ # and may attempt to render JSON data as HTML if the URL ends in .html
+
+ original_tg_jsonify_GenericJSON_encode = tg.jsonify.GenericJSON.encode
+ escape_pattern_with_lt = re.compile(simplejson.encoder.ESCAPE.pattern.rstrip(']') + '<' + ']')
+
+ @h.monkeypatch(tg.jsonify.GenericJSON)
+ def encode(self, o):
+ # ensure_ascii=False forces encode_basestring() to be called instead of
+ # encode_basestring_ascii() and encode_basestring_ascii may likely be c-compiled
+ # and thus not monkeypatchable
+ with h.push_config(self, ensure_ascii=False), \
+ h.push_config(simplejson.encoder, ESCAPE=escape_pattern_with_lt), \
+ mock.patch.dict(simplejson.encoder.ESCAPE_DCT, {'<': r'\u003C'}):
+ return original_tg_jsonify_GenericJSON_encode(self, o)
+
+
# must be saved outside the newrelic() method so that multiple newrelic()
# calls (e.g. during tests) don't cause the patching to get applied to itself
# over and over
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/1843655a/ForgeWiki/forgewiki/tests/functional/test_rest.py
----------------------------------------------------------------------
diff --git a/ForgeWiki/forgewiki/tests/functional/test_rest.py b/ForgeWiki/forgewiki/tests/functional/test_rest.py
index 0025150..0b93680 100644
--- a/ForgeWiki/forgewiki/tests/functional/test_rest.py
+++ b/ForgeWiki/forgewiki/tests/functional/test_rest.py
@@ -19,7 +19,9 @@
import json
-from nose.tools import assert_equal
+from nose.tools import assert_equal, assert_in
+import simplejson
+import tg
from allura.lib import helpers as h
from allura.tests import decorators as td
@@ -76,3 +78,20 @@ class TestWikiApi(TestRestApiBase):
r = self.api_get(u'/rest/p/test/wiki/tést/'.encode('utf-8'))
assert_equal(r.json['text'], data['text'])
assert_equal(r.json['labels'], data['labels'].split(','))
+
+ # http://blog.watchfire.com/wfblog/2011/10/json-based-xss-exploitation.html
+ def test_json_encoding_security(self):
+ self.api_post('/rest/p/test/wiki/foo.html',
+ text='foo <img src=x onerror=alert(1)> bar')
+ r = self.api_get('/rest/p/test/wiki/foo.html')
+ # raw text is not an HTML tag
+ assert_in(r'foo \u003Cimg src=x onerror=alert(1)> bar', r.body)
+ # and json still is parsed into correct content
+ assert_equal(r.json['text'], 'foo <img src=x onerror=alert(1)> bar')
+
+ def test_json_encoding_directly(self):
+ # used in @expose('json')
+ assert_equal(tg.jsonify.encode('<'), '"\u003C"')
+ # make sure these are unchanged
+ assert_equal(json.dumps('<'), '"<"')
+ assert_equal(simplejson.dumps('<'), '"<"')