Log in

Mohammed

tatau.dev@gmail.com

Components

Access Control/Authorization

See access control.

What mechanisms are there to restrict URL access?

What permissions model is available?

How hard is it to define who should be able to access what?

In web2py all URLs are of the form

http://hostname/<application>/<controller>/<function>/....

and if they are not of this form, they are mapped into URLs of this form using regular expressions by routes.py. URLs are then mapped into function calls. Web2py first validates the URL using regular expressions then checks that the <application> exists and that it contains a controller file called <controller>.py which contains a function <function>. If all these conditions are true, the function is executed. The function is responsible for its authentication. This can be achieved using Python decorators. For example

@auth.requires_login()
def index(): return dict()

The decorator replaces the function <index> with a new <index> function that checks if the user is logged in. If they are not, it redirects to a login page. Otherwise it executes the function.

web2py provides decorators that implement Role Based Access Control (RBAC). Here are examples of decorators:

@auth.requires_login()
@auth.requires_membership(role='administrator')
@auth.requires_permission('edit','tablename',record_id)

All functions can be decorated whether they are implemented as actions or not. Roles and permissions are arbitrary and user defined. Permissions can be associated to any object referenced by its name, including to individual database records.

There are two mechanisms to deal with specific situations:

1. If a user uploads a file trough a form, the file can be retrieved via the built-in download action. This function can be instructed to check the user's permissions to download the file.

db.mytable.myuploadfield.authorize=lambda filename:mycheck(filename)

2. web2py generates forms from database information. The RBAC adopts conventions to limit access to tables, records, and columns.

Authentication

See authentication.

What authentication methods are available?

  • email and password via a form (default)
  • username and password via a form
  • email and password via basic auth
  • username and password via a basic auth
  • pam
  • LDAP
  • Twitter
  • Facebook
  • LinkedIn
  • Gmail

Different methods can be piped together. Other methods are available via third party modules: OpenID, RPX.

What hash method is used on user credentials? Is it salted?

Multiple methods are possible.

(This needs to be clarified. It is unclear what effect the configuration has and what effects the CRYPT parameters have.)

If no key/salt is provided, web2py uses MD5, but if a key/salt is provided (and the scaffolding application generates one automatically) it uses HMAC+MD5 or HMAC+SHA512.

class CRYPT(object):
    """
    example::

        INPUT(_type='text', _name='name', requires=CRYPT())

    encodes the value on validation with a digest.

    If no arguments are provided CRYPT uses the MD5 algorithm.
    If the key argument is provided the HMAC+MD5 algorithm is used.
    If the digest_alg is specified this is used to replace the
    MD5 with, for example, SHA512. The digest_alg can be
    the name of a hashlib algorithm as a string or the algorithm itself.
    """

    def __init__(self, key=None, digest_alg=None):
        if key and not digest_alg:
            if key.count(':')==1:
                (digest_alg, key) = key.split(':')
        if not digest_alg:
            digest_alg = 'md5' # for backward compatibility
        self.key = key
        self.digest_alg = digest_alg

    def __call__(self, value):
        if self.key:
            alg = get_digest(self.digest_alg)
            return (hmac.new(self.key, value, alg).hexdigest(), None)
        else:
            return (hash(value, self.digest_alg), None)

Could account creation overwrite an existing account?

No. Default validators prevent it.

Could the change password or recover password functions be used maliciously?

There are two mechanism for recovering passwords. The old one only requires a user email, resets the password for the user and emails a new password. It can be used maliciously by an attacker to force a user to reset his/her password but it cannot be used to gain access to the system. This mechnism is now deprecated. The new mechanism can only be user to trigger an email to request password reset. Only the recipient of the email can trigger the password reset.

Both mechanisms can be bypassed if a third party authentication mechanism is used such as facebook.

Configuration

See configuration.

Are the framework dependencies up to date? Are there security vulnerabilities in the versions used by the framework?

Yes as far as we know. Anyway web2py depends only on Python and its default modules. web2py includes some contributed modules (rocket web server, fcgi adapter, markdown, simplejson). In the history of web2py the only contributed module to have a security issue was markdown (it allowed a XSS attack). The web2py community fixed the problem and submitted a patch to the official markdown distribution.

Are there default account passwords?

No.

Is there an exception handler, will it run in production? Are there notes and reminders to turn it off in configuration?

All exceptions are logged (whether in production or not). They are only visible to the administrator of the system.

Cross-Site Request Forgery (CSRF)

See cross-site request forgery.

Are there GET requests that change state? This helps enable CSRF.

What mechanisms are there to add CSRF tokens to forms? How easy is it to use?

web2py forms can include a one time security token hidden in the form. This prevents CSRF and also prevents problems with accidental double form submission. Works with POST and GET. It is up to the developer to use GET or POST to change the state (although we recommend POST and the built-in CRUD requires POST). Consider this logic for form processing:

def index():
    form=SQLFORM.factory(Field('name',requires=IS_NOT_EMPTY()))
    if form.accepts(request.vars,session):
        response.flash='hello '+form.vars.name
    return dict(form=form)

it is the second argument of form.accepts ('session') that triggers the CSRF prevention mechanism. Omitting this argument will disable it. We use this argument in all examples in the documentation except in those equation when forms do not change the state.

Cross-Site Scripting (XSS)

See cross-site scripting.

Warning:

web2py's HTML escaping will not protect you from Cross-Site Scripting if you do not quote your HTML attributes.

Always quote your HTML attributes!

What escaping does the template engine do to prevent XSS? What does the developer need to do to use it?

The template engine does 5 character HTML entity escaping on everything by default. Here are some examples

{{="hello <world>"}} -> "hello &lt;world&gt;"
{{=DIV("hello",SPAN("<world>"))}} -> "<div>hello<span>&lt;world&gt;</span></div>"

The escaping can be turned off with or without sanitization using the XML keyword:

{{=XML("hello <world>")}} -> "hello <world>"
{{=XML("hello <span><world></span>",sanitize=True}} -> "hello <span>&lt;world&gt;</span>"

It is possible to specify the list of allowed tags and tags attributes in sanitization.

Below is the escaping method used in 1.81.3. It is using the standard library's cgi module, but manually escaping the single quote.

Warning:

Up to and including web2py 1.80.1, the default HTML escaping does not escape quotes. This means your site is likely vulnerable to Cross-Site Scripting if you have user-supplied data in HTML attributes. This was fixed in 1.81.1 and we highly recommend upgrading.

def xmlescape(data, quote = True):
    """
    returns an escaped string of the provided data

    :param data: the data to be escaped
    :param quote: optional (default False)
    """

    # first try the xml function
    try:
        return data.xml()
    except AttributeError:
        pass
    except TypeError:
        pass

    # otherwise, make it a string
    if not isinstance(data, (str, unicode)):
        data = str(data)
    elif isinstance(data, unicode):
        data = data.encode('utf8', 'xmlcharrefreplace')

    # ... and do the escaping
    data = cgi.escape(data, quote).replace("'","&#x27;")
    return data

Are there vulnerabilities in the template engine?

None are known.

Theoretically there are runaway problems in the regular expression parser. We are not aware of this problem in CPython but there is a known bug in Java regular expressions parser that could theoretically create problems in web2py+Jython. This is not a web2py specific issue anyway but a Java issue.

Cryptography

See cryptography.

We'd like to see frameworks provide the structure to do solid encryption in applications even if the framework itself doesn't need it. A configuration toggle to encrypt stored user data (if such a thing is handled by the framework) would be wonderful as well.

Does the framework provide a system for applications to encrypt data?

What algorithm is it using?

Where is the key stored?

Who can access the encrypted data?

Can developers easily encrypt user data?

web2py does not include a mechanism for encrypting data. web2py does not encrypt data except at the HTTPS layer or (optional) for SSH tunnel to communicate with the database and/or the administrator.

Injection

See injection.

What interpreters is the framework capable of using?

web2py applications are Python programs so they have access to eval, exec and os.system but we do not recommend using them.

How does it access a database?

This is done via a database abtraction layer. Unless this is bypassed, SQL injections are not possible (except for a known problem with Postgresql 8.1 and earlier).

What about LDAP queries or OS commands?

LPAD are usually accessed via the auth API and therefore there is no problem. Access to OS commands is not restricted by web2py.

What escaping is done on data headed to an interpreter?

web2py does not send any data coming from users to the interpreter. web2py does send to the interpreter data coming from the administrator (defined and the the developer who has access to the web based ide, i.e. the programmer of the system).

Can a developer write raw SQL? If so, proper escaping is almost certainly not done. A warning should be written.

This is rarely necessary in web2py. The pitfalls are documented.

Object Reference

See object reference.

Is there a mechanism to proxy direct object references through an indirect reference?

Redirects and Forwards

See redirects and forwards.

If there is skeleton code in the framework, can a URL be crafted to redirect to an arbitrary site?

In the framework documentation for doing redirects and forwards, is there a warning about using user-supplied data in the redirect location?

Session Management

See session management.

How are session IDs generated?

A combination of the standard lib's uuid4 and uuid1. This is the uuid generation code from version 1.80:

web2py_uuid_locker = thread.allocate_lock()
node_id = uuid.getnode()
milliseconds = int(time.time() * 1e3)

def rotate(i):
    a = random.randrange(256)
    b = (node_id >> 4*i) % 256
    c = (milliseconds >> 4*i) % 256
    return (a + b + c) % 256

def web2py_uuid():
    web2py_uuid_locker.acquire()
    try:
        bytes = [chr(rotate(i)) for i in range(16)]
        return str(uuid.UUID(bytes=bytes, version=4))
    finally:
        web2py_uuid_locker.release()

Are session IDs ever exposed in the URL? Leaking session IDs through logs, referrer headers, etc can lead to compromised accounts.

No. SIDS are only communicated via cookies.

Are session IDs accepted through GET or POST data? This would aid in session fixation attacks.

No.

Do session IDs timeout?

Sessions IDs do not. Note that web2py encapsulates authentication tokens inside the session. Authentication tokens do time out, but sessions do not.

Can users log out?

Yes.

Are session IDs changed after login?

No, but it can be done.

Are authentication tokens changed after login?

Transport Layer Security

See transport layer security.

Can the framework be used with SSL? What is required and how difficult is it to set up?

Yes. Just run the built-in web server with a command line option (what option?) that specifies the location of SSL key and certificate. Or use apache with mod_ssl.

When used in SSL mode, do session cookies have the 'secure' flag set?

Not by default. It can be set by the developer:

session.secure()

Validation

See validation.

Is there a mechanism available that allows developers to validate input data against a schema? Regex validation as well as custom attributes like numeric comparison. Having developers directly use the re module does not count.


  • Version: latest
  • Edited by Mohammed Gamal on 8/11/11 7:11 AM
  • History
  • Edit

An OWASP project created by Craig Younkins

Powered by Moe and Google App Engine