Fix multiple Cross-Site Scripting (XSS) vulnerabilities.

* Ensure user emails are properly escaped

User emails in the Users and Groups panel are being passed through the
urlize filter to transform them into clickable links. However, urlize
expects input to be already escaped and safe. We should make sure to
escape the strings first as email addresses are not validated and can
contain any type of string.

Closes-Bug: #1320235

 * Ensure network names are properly escaped in the Launch Instance menu

Closes-Bug: #1322197

 * Escape the URLs generated for the Horizon tables

When generating the Horizon tables, there was an assumption that only
the anchor text needed to be escaped. However some URLs are generated
based on user-provided data and should be escaped as well.

 * Use 'reverse' to generate the Resource URLs in the stacks tables

Closes-Bug: #1308727

Change-Id: Ic8a92e69f66c2d265a802f350e30f091181aa42e
This commit is contained in:
Julie Pichon 2014-05-22 16:45:03 +01:00
parent 82bf9ee061
commit de4466d88b
6 changed files with 29 additions and 6 deletions

View File

@ -51,8 +51,15 @@ horizon.instances = {
$(this.get_network_element("")).each(function(){
var $this = $(this);
var $input = $this.children("input");
var name = $this.text().replace(/^\s+/,"")
.replace(/&/g, '&')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#x27;')
.replace(/\//g, '&#x2F;');
var network_property = {
name:$this.text().replace(/^\s+/,""),
name:name,
id:$input.attr("id"),
value:$input.attr("value")
};

View File

@ -692,7 +692,9 @@ class Cell(html.HTMLElement):
self.column.link_attrs.items()])
# Escape the data inside while allowing our HTML to render
data = mark_safe('<a href="%s" %s>%s</a>' % (
self.url, link_attrs, escape(unicode(data))))
(escape(self.url),
link_attrs,
escape(unicode(data)))))
return data
@property

View File

@ -159,7 +159,8 @@ class AddMembersLink(tables.LinkAction):
class UsersTable(tables.DataTable):
name = tables.Column('name', verbose_name=_('User Name'))
email = tables.Column('email', verbose_name=_('Email'),
filters=[defaultfilters.urlize])
filters=[defaultfilters.escape,
defaultfilters.urlize])
id = tables.Column('id', verbose_name=_('User ID'))
enabled = tables.Column('enabled', verbose_name=_('Enabled'),
status=True,

View File

@ -131,7 +131,9 @@ class UsersTable(tables.DataTable):
email = tables.Column('email', verbose_name=_('Email'),
filters=(lambda v: defaultfilters
.default_if_none(v, ""),
defaultfilters.urlize))
defaultfilters.escape,
defaultfilters.urlize)
)
# Default tenant is not returned from Keystone currently.
#default_tenant = tables.Column('default_tenant',
# verbose_name=_('Default Project'))

View File

@ -115,11 +115,16 @@ class StacksTable(tables.DataTable):
ChangeStackTemplate)
def get_resource_url(obj):
return urlresolvers.reverse('horizon:project:stacks:resource',
args=(obj.stack_id, obj.resource_name))
class EventsTable(tables.DataTable):
logical_resource = tables.Column('resource_name',
verbose_name=_("Stack Resource"),
link=lambda d: d.resource_name,)
link=get_resource_url)
physical_resource = tables.Column('physical_resource_id',
verbose_name=_("Resource"),
link=mappings.resource_to_url)
@ -164,7 +169,7 @@ class ResourcesTable(tables.DataTable):
logical_resource = tables.Column('resource_name',
verbose_name=_("Stack Resource"),
link=lambda d: d.resource_name)
link=get_resource_url)
physical_resource = tables.Column('physical_resource_id',
verbose_name=_("Resource"),
link=mappings.resource_to_url)

View File

@ -99,6 +99,9 @@ class StackEventsTab(tabs.Tab):
stack_identifier = '%s/%s' % (stack.stack_name, stack.id)
events = api.heat.events_list(self.request, stack_identifier)
LOG.debug('got events %s' % events)
# The stack id is needed to generate the resource URL.
for event in events:
event.stack_id = stack.id
except Exception:
events = []
messages.error(request, _(
@ -124,6 +127,9 @@ class StackResourcesTab(tabs.Tab):
stack_identifier = '%s/%s' % (stack.stack_name, stack.id)
resources = api.heat.resources_list(self.request, stack_identifier)
LOG.debug('got resources %s' % resources)
# The stack id is needed to generate the resource URL.
for r in resources:
r.stack_id = stack.id
except Exception:
resources = []
messages.error(request, _(