You are not logged in Log in Join
You are here: Home » Members » efge » Zope and web applications security » View Document

Log in
Name

Password

 

Zope and web applications security

Zope and web applications security

By Florent Guillaume, Nuxeo <fg at nuxeo.com>

Summary

Zope sites are subject to several standard flaws of web applications. These flows are now well known in the security community, and should be dealt with urgently in the context of Zope, or at least recognized as potential problems.

  • If your users are able to publish HTML (through files, structured text or something comparable) and you use cookie authentication, you lose all security. This is one aspect of the so called "cross-site scripting" flaws.
  • In many cases innocuous-looking links can in fact make you unwittingly do fatal actions to your site, like deleting things or shutting down the site.

Cookie authentication considered harmful

The problem

Javascript code included in a page can examine any cookie destined for the current site if the cookie's Path is a prefix of the current page's URL.

In Zope, authentication cookies are use with products like Cookie Crumbler, which are magically active on any page during link traversal. In order to be effective, the cookie Path must be a prefix of all accessed pages, not just the login page. The purpose of the Path parameter of the cookie is then completely defeated.

But this means that any page can retrieve the authentication cookies of the visitors if they exist. In turn, Javascript code could send those cookies to any site they desire, without the visitor being aware of it.

For instance the following line is Javascript-generated:

Untrusted user-generated content

In general this wouldn't be a problem because the site developer writes the Javascript and knows what he does, except that in the case of content-oriented sites the user can produce part of the page. In Zope this is the case with DTML Documents, CMF Documents, any structured-text output, etc.

This means that if you base some of the site security on user authentication and that you use cookies to do it, your site's security is just a figment of your imagination.

Partial solution

If Zope wants to display user-generated content, it should preemptively filter anything it doesn't know about.

This is very feasible for structured text, but it's much more difficult for HTML documents, where you would need to have a light HTML filter that outputs only known tags and no <script> tags for instance. (Doing filtering the other way, by removing known bad tags, is a neverending race against future active tags and browser parsing bugs.)

Quoting other untrusted input is vital

Anything that outputs text on your site should protect itself from outputing valid HTML (thus Javascript) code from untrusted input. This includes:

  • error message that display the current URL or a parameter
  • feedback from a search that displays the current search string
  • user-generated content, as described above

Note that "untrusted" input can come via roundabout ways. For instance the user could type a string, the string be stored in a database, then later the database queried and the string displayed.

Zope has several ways to quote output:

  • DTML code should always use either <dtml-val> with the html_quote attribute, or use &dtml-foo;, but be aware that &dtml.missing-foo; does not quote the output.
  • Python Scripts should be careful (XXX).
  • ZPT code should never use "structure" except in known good cases.

I haven't done a full security audit of all Zope code, but a lot of the CMF DTML code and even sometimes the ZMI does simple minded things like:

            <dtml-var title_or_id>
            <dtml-var Title>
            <dtml-var description>
            <dtml-var Description fmt="structured-text">
            <dtml-var CookedBody>
            &dtml.missing-Type;
            &dtml.-HistoryBatchSize;

Every single one of those should be converted to either use html_quote, or a simpler &dtml-foo; form. Even if it's an href (yes, content in href should be url_quoted anyway for correct semantics).

Your cookies are doomed anyway

You must still be aware that a lot of browsers have bugs that make it possible to retrieve the cookie anyway from another entirely different site, which means cookies are completely useless for authentication.

Doing without cookies

A fallback to standard HTTP Authentication should be considered. It's not perfect but it's in most ways better than cookies.

References

Link hijacking

The problem

Suppose you're reading a weblog somewhere, and you see a user-posted link that looks interesting to you, http://somesite/info.html. You click on it (it looked harmless isn't it ?), and suddenly it redirects you to http://yourzopesite.com/manage_delObjects?ids:list=acl_users. It works, because just before you were working on your site, so you're still authenticated with it. Blam you're in bad waters.

This problem does not only manifest itself with GET methods, as a POST can also easily be generated using Javascript.

In an actual case of such hijacking, Slashdot users used this stratagem to make others to post articles to a given thread. There wasn't even any use of redirection, because who reads the links anyway...

Solution

Any authenticated action that has lasting effects (destruction, creation, validation, site shutdown, etc.) should be validated by the server to ensure that it does indeed come from a known good context. A good context would typically be the fact that the user is known to come from a legitimate page proposing the action, and has voluntarily clicked on a link or button.

A Referer test could be a first measure, but it's not perfect, as it could shut out users who have either a broken browser or have decided to filter out the Referer for privacy reasons. It's an acceptable interim solution though.

One feasible complete solution is described below, in the context of an example where a document destruction is requested:

  • The servers generates a cryptographic token T that is based on:
    • the user,
    • the current time.

    This token must be such that it cannot be spoofed. For instance:

    • H = a hash function, like MD5,
    • S = a global server secret,
    • T = time || H(S || H(S || username || time)).

    (The hash is done this way, doubled, on cryptographic experts' advice).

  • This token is attached in the page asking if the user wants to delete a given document, either in the FORM or in an URL parameter,
  • When the user clicks, the servers receives the token and, based on the user identity, verifies its integrity and the fact that it's not outdated (to prevent replay attacks),
  • If it's outdated, the server could restart the procedure and reask for confirmation,
  • If it's correct then the document can be destroyed.

All this is transparent to the user, except when he leaves a page open for a long time and then clicks on "delete".

What's needed is an framework in Zope to make this kind of token passing easy to deal with.

References

Additional references are sought.

Session IDs in the URL and Referer

The problem

I'm not sure this problem presents itself using current Zope tools, but it should be mentionned.

Here is the scenario:

  • You are authenticated in a trusted Zope site using a session ID that is put in the URL,
  • In this site, you click on a link to an external site,
  • The external site's owner, through its logs or any Javascript in the destination page, is able to recover the Referer, which in our case contains the full session ID,
  • He can simply use this URL and browse the trusted site with your session ID, which could mean your full identity if authentication is done through session IDs only.

This problem has plagued nearly every webmail program out there, for instance.

Solution

A first solution would be to not rely only on session IDs, but also on another form of authentication. This way, recovering the session ID is not sufficient to impersonate you.

A more complex solution is to not point directly to external sites, but instead use an intermediate redirection step that cleans up the Referer. So any external link, say http://google.com, would be generated as http://yoursite/redirect?dest=http%3a//google.com, then the redirect script would have to use a way to redirect to the site in the parameter, using a method that does not produce a Referer.

The following methods will have to be investigated for correct behaviour (I did it before but am not sure of the result I got). Not that the behaviour could even be browser-dependant.

  • doing a simple redirect using Location (I think it keeps the original Referer in most browsers),
  • using a Refresh header,
  • using Javascript to change the document.location,
  • invite the user to click on a link. This is foolproof but very inconvenient.

References

Additional references are sought.