Mercurial > kallithea
view docs/usage/email.rst @ 6532:33b71a130b16
templates: properly escape inline JavaScript values
TLDR: Kallithea has issues with escaping values for use in inline JS.
Despite judicious poking of the code, no actual security vulnerabilities
have been found, just lots of corner-case bugs. This patch fixes those,
and hardens the code against actual security issues.
The long version:
To embed a Python value (typically a 'unicode' plain-text value) in a
larger file, it must be escaped in a context specific manner. Example:
>>> s = u'<script>alert("It\'s a trap!");</script>'
1) Escaped for insertion into HTML element context
>>> print cgi.escape(s)
<script>alert("It's a trap!");</script>
2) Escaped for insertion into HTML element or attribute context
>>> print h.escape(s)
<script>alert("It's a trap!");</script>
This is the default Mako escaping, as usually used by Kallithea.
3) Encoded as JSON
>>> print json.dumps(s)
"<script>alert(\"It's a trap!\");</script>"
4) Escaped for insertion into a JavaScript file
>>> print '(' + json.dumps(s) + ')'
("<script>alert(\"It's a trap!\");</script>")
The parentheses are not actually required for strings, but may be needed
to avoid syntax errors if the value is a number or dict (object).
5) Escaped for insertion into a HTML inline <script> element
>>> print h.js(s)
("\x3cscript\x3ealert(\"It's a trap!\");\x3c/script\x3e")
Here, we need to combine JS and HTML escaping, further complicated by
the fact that "<script>" tag contents can either be parsed in XHTML mode
(in which case '<', '>' and '&' must additionally be XML escaped) or
HTML mode (in which case '</script>' must be escaped, but not using HTML
escaping, which is not available in HTML "<script>" tags). Therefore,
the XML special characters (which can only occur in string literals) are
escaped using JavaScript string literal escape sequences.
(This, incidentally, is why modern web security best practices ban all
use of inline JavaScript...)
Unsurprisingly, Kallithea does not do (5) correctly. In most cases,
Kallithea might slap a pair of single quotes around the HTML escaped
Python value. A typical benign example:
$('#child_link').html('${_('No revisions')}');
This works in English, but if a localized version of the string contains
an apostrophe, the result will be broken JavaScript. In the more severe
cases, where the text is user controllable, it leaves the door open to
injections. In this example, the script inserts the string as HTML, so
Mako's implicit HTML escaping makes sense; but in many other cases, HTML
escaping is actually an error, because the value is not used by the
script in an HTML context.
The good news is that the HTML escaping thwarts attempts at XSS, since
it's impossible to inject syntactically valid JavaScript of any useful
complexity. It does allow JavaScript errors and gibberish to appear on
the page, though.
In these cases, the escaping has been fixed to use either the new 'h.js'
helper, which does JavaScript escaping (but not HTML escaping), OR the
new 'h.jshtml' helper (which does both), in those cases where it was
unclear if the value might be used (by the script) in an HTML context.
Some of these can probably be "relaxed" from h.jshtml to h.js later, but
for now, using h.jshtml fixes escaping and doesn't introduce new errors.
In a few places, Kallithea JSON encodes values in the controller, then
inserts the JSON (without any further escaping) into <script> tags. This
is also wrong, and carries actual risk of XSS vulnerabilities. However,
in all cases, security vulnerabilities were narrowly avoided due to other
filtering in Kallithea. (E.g. many special characters are banned from
appearing in usernames.) In these cases, the escaping has been fixed
and moved to the template, making it immediately visible that proper
escaping has been performed.
Mini-FAQ (frequently anticipated questions):
Q: Why do everything in one big, hard to review patch?
Q: Why add escaping in specific case FOO, it doesn't seem needed?
Because the goal here is to have "escape everywhere" as the default
policy, rather than identifying individual bugs and fixing them one
by one by adding escaping where needed. As such, this patch surely
introduces a lot of needless escaping. This is no different from
how Mako/Pylons HTML escape everything by default, even when not
needed: it's errs on the side of needless work, to prevent erring
on the side of skipping required (and security critical) work.
As for reviewability, the most important thing to notice is not where
escaping has been introduced, but any places where it might have been
missed (or where h.jshtml is needed, but h.js is used).
Q: The added escaping is kinda verbose/ugly.
That is not a question, but yes, I agree. Hopefully it'll encourage us
to move away from inline JavaScript altogether. That's a significantly
larger job, though; with luck this patch will keep us safe and secure
until such a time as we can implement the real fix.
Q: Why not use Mako filter syntax ("${val|h.js}")?
Because of long-standing Mako bug #140, preventing use of 'h' in
filters.
Q: Why not work around bug #140, or even use straight "${val|js}"?
Because Mako still applies the default h.escape filter before the
explicitly specified filters.
Q: Where do we go from here?
Longer term, we should stop doing variable expansions in script blocks,
and instead pass data to JS via e.g. data attributes, or asynchronously
using AJAX calls. Once we've done that, we can remove inline JavaScript
altogether in favor of separate script files, and set a strict Content
Security Policy explicitly blocking inline scripting, and thus also the
most common kind of cross-site scripting attack.
author | Søren Løvborg <sorenl@unity3d.com> |
---|---|
date | Tue, 28 Feb 2017 17:19:00 +0100 |
parents | 6b865fcfed20 |
children | e223c36e5b68 |
line wrap: on
line source
.. _email: ============== Email settings ============== The Kallithea configuration file has several email related settings. When these contain correct values, Kallithea will send email in the situations described below. If the email configuration is not correct so that emails cannot be sent, all mails will show up in the log output. Before any email can be sent, an SMTP server has to be configured using the configuration file setting ``smtp_server``. If required for that server, specify a username (``smtp_username``) and password (``smtp_password``), a non-standard port (``smtp_port``), whether to use "SSL" when connecting (``smtp_use_ssl``) or use STARTTLS (``smtp_use_tls``), and/or specify special ESMTP "auth" features (``smtp_auth``). For example, for sending through gmail, use:: smtp_server = smtp.gmail.com smtp_username = username smtp_password = password smtp_port = 465 smtp_use_ssl = true Application emails ------------------ Kallithea sends an email to `users` on several occasions: - when comments are given on one of their changesets - when comments are given on changesets they are reviewer on or on which they commented regardless - when they are invited as reviewer in pull requests - when they request a password reset Kallithea sends an email to all `administrators` upon new account registration. Administrators are users with the ``Admin`` flag set on the *Admin > Users* page. When Kallithea wants to send an email but due to an error cannot correctly determine the intended recipients, the administrators and the addresses specified in ``email_to`` in the configuration file are used as fallback. Recipients will see these emails originating from the sender specified in the ``app_email_from`` setting in the configuration file. This setting can either contain only an email address, like `kallithea-noreply@example.com`, or both a name and an address in the following format: `Kallithea <kallithea-noreply@example.com>`. However, if the email is sent due to an action of a particular user, for example when a comment is given or a pull request created, the name of that user will be combined with the email address specified in ``app_email_from`` to form the sender (and any name part in that configuration setting disregarded). The subject of these emails can optionally be prefixed with the value of ``email_prefix`` in the configuration file. A Kallithea-specific header indicating the email type will be added to each email. This header can be used for email filtering. The header is of the form: X-Kallithea-Notification-Type: <type> where ``<type>`` is one of: - ``pull_request``: you are invited as reviewer in a pull request - ``pull_request_comment``: a comment was given on a pull request - ``cs_comment``: a comment was given on a changeset - ``registration``: a new user was registered - ``message``: another type of email Error emails ------------ When an exception occurs in Kallithea -- and unless interactive debugging is enabled using ``set debug = true`` in the ``[app:main]`` section of the configuration file -- an email with exception details is sent by WebError_'s ``ErrorMiddleware`` to the addresses specified in ``email_to`` in the configuration file. Recipients will see these emails originating from the sender specified in the ``error_email_from`` setting in the configuration file. This setting can either contain only an email address, like `kallithea-noreply@example.com`, or both a name and an address in the following format: `Kallithea Errors <kallithea-noreply@example.com>`. *Note:* The WebError_ package does not respect ``smtp_port`` and assumes the standard SMTP port (25). If you have a remote SMTP server with a different port, you could set up a local forwarding SMTP server on port 25. References ---------- - `Error Middleware (Pylons documentation) <http://pylons-webframework.readthedocs.org/en/latest/debugging.html#error-middleware>`_ - `ErrorHandler (Pylons modules documentation) <http://pylons-webframework.readthedocs.org/en/latest/modules/middleware.html#pylons.middleware.ErrorHandler>`_ .. _WebError: https://pypi.python.org/pypi/WebError