summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCristianFiorentino <cristian.fiorentino@intel.com>2014-03-10 17:36:31 -0300
committerAkihiro Motoki <motoki@da.jp.nec.com>2014-04-09 00:04:39 +0900
commit1b0106e2804a45e641433c4bd459e6bed85521c3 (patch)
tree4ec8b108dd84e2d672d0b29e1c49d5d9218a9657
parentd566f620ed60db0a16bc59d2d34b516d882d19e8 (diff)
downloadhorizon-2014.1.rc2.tar.gz
Introduces escaping in Horizon/Orchestration2014.1.rc22014.1
1) Escape help_text a second time to avoid bootstrap tooltip XSS issue The "Description" parameter in a Heat template is used to populate a help_text tooltip in the dynamically generated Heat form. Bootstrap inserts this tooltip into the DOM using .html() which undoes any escaping we do in Django (it should be using .text()). This was fixed by forcing the help_text content to be escaped a second time. The issue itself is mitigated in bootstrap.js release 2.0.3 (ours is currently 2.0.1). 2) Properly escape untrusted Heat template 'outputs' The 'outputs' parameter in a Heat template was included in a Django template with HTML autoescaping turned off. Malicious HTML content could be included in a Heat template and would be rendered by Horizon when details about a created stack were displayed. This was fixed by not disabling autoescaping and explicitly escaping untrusted values in any strings that are later marked "safe" to render without further escaping. Change-Id: Icd9f9d9ca77068b12227d77469773a325c840001 Closes-Bug: #1289033 Co-Authored-By: Kieran Spear <kispear@gmail.com>
-rw-r--r--horizon/templates/horizon/common/_form_fields.html7
-rw-r--r--openstack_dashboard/dashboards/project/stacks/mappings.py10
-rw-r--r--openstack_dashboard/dashboards/project/stacks/templates/stacks/_detail_overview.html3
-rw-r--r--openstack_dashboard/dashboards/project/stacks/tests.py17
4 files changed, 26 insertions, 11 deletions
diff --git a/horizon/templates/horizon/common/_form_fields.html b/horizon/templates/horizon/common/_form_fields.html
index 1fbe8461e..83cbfa37f 100644
--- a/horizon/templates/horizon/common/_form_fields.html
+++ b/horizon/templates/horizon/common/_form_fields.html
@@ -19,7 +19,12 @@
<span class="help-inline">{{ error }}</span>
{% endfor %}
{% endif %}
- <span class="help-block">{{ field.help_text }}</span>
+ {% comment %}
+ Escape help_text a second time here, to avoid an XSS issue in bootstrap.js.
+ This can most likely be removed once we upgrade bootstrap.js past 2.0.2.
+ Note: the spaces are necessary here.
+ {% endcomment %}
+ <span class="help-block">{% filter force_escape %} {{ field.help_text }} {% endfilter %} </span>
<div class="input">
{{ field }}
</div>
diff --git a/openstack_dashboard/dashboards/project/stacks/mappings.py b/openstack_dashboard/dashboards/project/stacks/mappings.py
index 296de64c1..28b0226c6 100644
--- a/openstack_dashboard/dashboards/project/stacks/mappings.py
+++ b/openstack_dashboard/dashboards/project/stacks/mappings.py
@@ -18,6 +18,8 @@ import re
from django.core.urlresolvers import reverse
from django.template.defaultfilters import register # noqa
+from django.utils import html
+from django.utils import safestring
import six.moves.urllib.parse as urlparse
from openstack_dashboard.api import swift
@@ -76,11 +78,15 @@ def stack_output(output):
if not output:
return u''
if isinstance(output, dict) or isinstance(output, list):
- return u'<pre>%s</pre>' % json.dumps(output, indent=2)
+ json_string = json.dumps(output, indent=2)
+ safe_output = u'<pre>%s</pre>' % html.escape(json_string)
+ return safestring.mark_safe(safe_output)
if isinstance(output, basestring):
parts = urlparse.urlsplit(output)
if parts.netloc and parts.scheme in ('http', 'https'):
- return u'<a href="%s" target="_blank">%s</a>' % (output, output)
+ url = html.escape(output)
+ safe_link = u'<a href="%s" target="_blank">%s</a>' % (url, url)
+ return safestring.mark_safe(safe_link)
return unicode(output)
diff --git a/openstack_dashboard/dashboards/project/stacks/templates/stacks/_detail_overview.html b/openstack_dashboard/dashboards/project/stacks/templates/stacks/_detail_overview.html
index f391d80d7..0ce627a7d 100644
--- a/openstack_dashboard/dashboards/project/stacks/templates/stacks/_detail_overview.html
+++ b/openstack_dashboard/dashboards/project/stacks/templates/stacks/_detail_overview.html
@@ -36,9 +36,8 @@
<dt>{{ output.output_key }}</dt>
<dd>{{ output.description }}</dd>
<dd>
- {% autoescape off %}
{{ output.output_value|stack_output }}
- {% endautoescape %}</dd>
+ </dd>
{% endfor %}
</dl>
</div>
diff --git a/openstack_dashboard/dashboards/project/stacks/tests.py b/openstack_dashboard/dashboards/project/stacks/tests.py
index 4c364c859..c13d0bb60 100644
--- a/openstack_dashboard/dashboards/project/stacks/tests.py
+++ b/openstack_dashboard/dashboards/project/stacks/tests.py
@@ -17,6 +17,7 @@ import json
from django.core import exceptions
from django.core.urlresolvers import reverse
from django import http
+from django.utils import html
from mox import IsA # noqa
@@ -78,12 +79,16 @@ class MappingsTests(test.TestCase):
self.assertEqual(u'foo', mappings.stack_output('foo'))
self.assertEqual(u'', mappings.stack_output(None))
- self.assertEqual(
- u'<pre>[\n "one", \n "two", \n "three"\n]</pre>',
- mappings.stack_output(['one', 'two', 'three']))
- self.assertEqual(
- u'<pre>{\n "foo": "bar"\n}</pre>',
- mappings.stack_output({'foo': 'bar'}))
+ outputs = ['one', 'two', 'three']
+ expected_text = """[\n "one", \n "two", \n "three"\n]"""
+
+ self.assertEqual(u'<pre>%s</pre>' % html.escape(expected_text),
+ mappings.stack_output(outputs))
+
+ outputs = {'foo': 'bar'}
+ expected_text = """{\n "foo": "bar"\n}"""
+ self.assertEqual(u'<pre>%s</pre>' % html.escape(expected_text),
+ mappings.stack_output(outputs))
self.assertEqual(
u'<a href="http://www.example.com/foo" target="_blank">'