view docs/upgrade.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) &lt;script&gt;alert("It's a trap!");&lt;/script&gt; 2) Escaped for insertion into HTML element or attribute context >>> print h.escape(s) &lt;script&gt;alert(&#34;It&#39;s a trap!&#34;);&lt;/script&gt; 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 f973b866fffc
children 2c3d30095d5e
line wrap: on
line source

.. _upgrade:

===================
Upgrading Kallithea
===================

This describes the process for upgrading Kallithea, independently of the
Kallithea installation method.

.. note::
    If you are upgrading from a RhodeCode installation, you must first
    install Kallithea 0.3.2 and follow the instructions in the 0.3.2
    README to perform a one-time conversion of the database from
    RhodeCode to Kallithea, before upgrading to the latest version
    of Kallithea.


1. Stop the Kallithea web application
-------------------------------------

This step depends entirely on the web server software used to serve
Kallithea, but in any case, Kallithea should not be running during
the upgrade.

.. note::
    If you're using Celery, make sure you stop all instances during the
    upgrade.


2. Create a backup of both database and configuration
-----------------------------------------------------

You are of course strongly recommended to make backups regularly, but it
is *especially* important to make a full database and configuration
backup before performing a Kallithea upgrade.

Back up your configuration
^^^^^^^^^^^^^^^^^^^^^^^^^^

Make a copy of your Kallithea configuration (``.ini``) file.

If you are using :ref:`rcextensions <customization>`, you should also
make a copy of the entire ``rcextensions`` directory.

Back up your database
^^^^^^^^^^^^^^^^^^^^^

If using SQLite, simply make a copy of the Kallithea database (``.db``)
file.

If using PostgreSQL, please consult the documentation for the ``pg_dump``
utility.

If using MySQL, please consult the documentation for the ``mysqldump``
utility.

Look for ``sqlalchemy.url`` in your configuration file to determine
database type, settings, location, etc.


3. Activate the Kallithea virtual environment (if any)
------------------------------------------------------

Verify that you are using the Python environment that you originally
installed Kallithea in by running::

    pip freeze

This will list all packages installed in the current environment. If
Kallithea isn't listed, activate the correct virtual environment.
See the appropriate installation page for details.


4. Install new version of Kallithea
-----------------------------------

Please refer to the instructions for the installation method you
originally used to install Kallithea.

If you originally installed using pip, it is as simple as::

    pip install --upgrade kallithea

If you originally installed from version control, it is as simple as::

    cd my-kallithea-clone
    hg pull -u
    pip install -e .


5. Upgrade your configuration
-----------------------------

Run the following command to upgrade your configuration (``.ini``) file::

    paster make-config Kallithea my.ini

This will display any changes made by the new version of Kallithea to your
current configuration, and attempt an automatic merge. It is recommended
that you check the contents after the merge.

.. note::
    Please always make sure your ``.ini`` files are up to date. Errors
    can often be caused by missing parameters added in new versions.

.. _upgrade_db:


6. Upgrade your database
------------------------

.. note::
    If you are *downgrading* Kallithea, you should perform the database
    migration step *before* installing the older version. (That is,
    always perform migrations using the most recent of the two versions
    you're migrating between.)

First, run the following command to see your current database version::

    alembic -c my.ini current

Typical output will be something like "9358dc3d6828 (head)", which is
the current Alembic database "revision ID". Write down the entire output
for troubleshooting purposes.

The output will be empty if you're upgrading from Kallithea 0.3.x or
older. That's expected. If you get an error that the config file was not
found or has no ``[alembic]`` section, see the next section.

Next, if you are performing an *upgrade*: Run the following command to
upgrade your database to the current Kallithea version::

    alembic -c my.ini upgrade head

If you are performing a *downgrade*: Run the following command to
downgrade your database to the given version::

    alembic -c my.ini downgrade 0.4

Alembic will show the necessary migrations (if any) as it executes them.
If no "ERROR" is displayed, the command was successful.

Should an error occur, the database may be "stranded" half-way
through the migration, and you should restore it from backup.

Enabling old Kallithea config files for Alembic use
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Kallithea configuration files created before the introduction of Alembic
(i.e. predating Kallithea 0.4) need to be updated for use with Alembic.
Without this, Alembic will fail with an error like this::

    FAILED: No config file 'my.ini' found, or file has no '[alembic]' section

If Alembic complains specifically about a missing ``alembic.ini``, it is
likely because you did not specify a config file using the ``-c`` option.
On the other hand, if the mentioned config file actually exists, you
need to append the following lines to it::

    [alembic]
    script_location = kallithea:alembic

Your config file should now work with Alembic.


7. Rebuild the Whoosh full-text index
-------------------------------------

It is recommended that you rebuild the Whoosh index after upgrading since
new Whoosh versions can introduce incompatible index changes.


8. Start the Kallithea web application
--------------------------------------

This step once again depends entirely on the web server software used to
serve Kallithea.

Before starting the new version of Kallithea, you may find it helpful to
clear out your log file so that new errors are readily apparent.

.. note::
    If you're using Celery, make sure you restart all instances of it after
    upgrade.


.. _virtualenv: http://pypi.python.org/pypi/virtualenv