xsspyramidchameleonzpt

Pyramid Chameleon template security for HTML and Javascript


Do Chameleon templates escape/strip XSS and HTML tags for variables? Would the following be safe?

<script type="text/javascript">

    var initialComments = ${comments};
    for (var i = 0; i < initialComments.length; i++) {
        initialComments[i].userId = initialComments[i].user_id;
    }
    var post = ${post}
    // ...

</script>

Solution

  • This is actually harder than it seems, and depends upon circumstances. If the output format is HTML, then the script contents are a special CDATA section, wherein the XML/SGML escapes are not interpreted. If the output format is XML, with XML content type, then the escapes work as expected. Even though it could be possible to patch Chameleon so that it understood the <script></script> element as special, currently it does not.

    When embedded in <script> tag, depending on a browser version, a sole </ or </script will end the script tag, making it vulnerable to XSS. Furthermore, a < can start a HTML comment as in <!--, and legacy considerations require that <script></script> can be written balanced WITHIN the script tag, thus the safest is to escape the < altogether in all strings.

    Another problem is that JSON is not a strict subset of JavaScript, allowing character strings like U+2028 and U+2029 break the script, if you use ensure_ascii=False:

    Thus the proper way to do this on python/chameleon, to embed within a <script> tag in HTML is to use:

    post_json = (json.dumps(foo, ensure_ascii=False)
        .replace('\u2028', r'\u2028')
        .replace('\u2029', r'\u2029')
        .replace('<', r'\u003c'))
    

    This is true for only content embedded in <script> tags.

    or if you just want to get unreadable escapes for pretty much all characters you can be content with:

    post_json = json.dumps(foo, ensure_ascii=True)\
        .replace('<', r'\u003c')
    

    and then embed with

    ${structure: post_json}
    

    I posted a feature request in the Python bug tracker to have a keyword argument to do this automatically, but it was rejected.

    The safer way to embed stuff is to store it in data-* attributes.

    UPDATE escaping </ alone is not enough.