Bottle Security Checklist
Dec 18, 2015
3 minute read

Bottle is a micro web-framework for Python, strongly resembling Flask. I was attracted by its even greater simplicity (no dependencies!) and I gave it a try in a few projects (e.x spamcan). Although Bottle’s documentation is very helpful, I noticed that it lacks detail in secure best practices.

Since micro-frameworks equal to small learning curves and small learning curves usually result to fast-paced development, I compiled a security checklist, covering the basics, that can be used as a reference when developing Bottle-based applications. Update, update, update!

No matter how small your framework’s codebase is, bugs will occur. Once in a while, they will be serious too. Always keep an eye for security patches and update to the latest stable release when possible.

SQL Injection

If your custom SQL queries accept user input you ’re going to have a hard time securing every single one of them. Unless you have a good reason not to, use Bottle-SQLalchemy.

Cross-Site Scripting (XSS)

Bottle uses the built-in SimpleTemplate Engine by default but also supports Mako, Cheetah and Jinja2 template engines.

When using SimpleTemplate, variables referenced inside curly brackets have their values automatically HTML-escaped. Escaping can be disabled by starting the expression with an exclamation mark. The following example is provided in the documentation:

    >>>template('Hello {{name}}!', name='<b>World</b>')
    u'Hello &lt;b&gt;World&lt;/b&gt;!'
    >>>template('Hello {{!name}}!', name='<b>World</b>')
    u'Hello <b>World</b>!'

Jinja2 has two modes of HTML escaping, automatic and manual. You should prefer automatic where all values are escaped unless stated otherwise using the safe filter e.x {{title | safe}}. Automatic escaping can be enabled using an environmental variable or a template statement

Mako template engine uses the h built-in flag to escape HTML characters e.x {{name | h }}. More on expression filtering in Mako here

Cheetah provides a WebSafe filter for HTML escaping.

CSRF

Bottle does not provide any built-in mechanism for CSRF protection. The easiest (and probably safest) solution is to use the Bottle Utils package which contains the bottle-utils-csrf (can be installed seperately). Usage is pretty simple.

File Uploads

Bottle documentation contains a rather insecure example for filetype validation in upload forms. File type validation should not rely only on file extensions, it should also validate the files' content. This can be easily performed using python-magic. A better, more secure example would be:

import magic

...

@app.post('/')
def upload():
    allowed_mimetypes = ['image/png']
    upload = request.files.get('uploadfile')
    filetype = magic.from_buffer(upload.file.read(), mime=True)
    if filetype in allowed_mimetypes:
        save_path = "uploads"
        upload.save(save_path)
        return 'OK'
    else:
        return "Filetype not allowed"

Cookies

Bottle has no built-in mechanism for session management. The official documentation suggests using beaker or writing your own implementation. Anyway, don’t forget to encrypt and mark all of your app’s sensitive cookies with HttpOnly and Secure (in case of HTTPS-enabled sites) flags. Both flags are disabled by default. Modified example code from documentation (assuming that login uses HTTPS):

@route('/login')
def do_login():
    username = request.forms.get('username')
    password = request.forms.get('password')
    if check_login(username, password):
        response.set_cookie("account", username, secret='some-secret-key',\
                             secure=True, httponly=True)
        return template("<p>Welcome {{name}}! You are now logged in.</p>", name=username)
    else:
        return "<p>Login failed.</p>"

Redirects

At the moment Bottle’s redirect() method supports absolute URLs. In order to avoid any potential malicious redirects, do not pass user-defined values to this method. This behaviour will change in 0.13, which is still under development, to comply with RFC7231.

Deployment

When you use Bottle code in production :

  • Do not run Bottle as root
  • Disable debug output
  • Avoid the built-in web server.

I plan to keep this post updated so if you have any comments, suggestions or additions don’t hesitate to contact me.