Caktus Security Policies

Caktus Group web security policies and best practices.

Table Of Contents

Previous topic

Caktus Security Policies and Practices

Next topic

Server Configurations

This Page

Application Development Considerations

When developing applications which will be accessed across the internet you must keep security in mind. Often innocuous looking code can expose either users or the application itself to security holes. The general principle is “never trust the client” or to assume that every client is malicious. Remember that information which comes from the client includes not only the request bodies (GET/POST) but also the HTTP headers, cookies, and the request path. Below are more tips to keep in mind or patterns to look out for when reviewing code.

Don’t Leave DEBUG on in Public

This goes equally for production and staging machines that aren’t protected from outside eyes. Enabling DEBUG turns on several things that can make sensitive information vulnerable to wanting eyes. The traceback page, in particular, dumps a lot of information out in public. Mitigate these issues with several safeguards.

Solutions:

  • Enable tracebacks by e-mail, to reduce your reliable on DEBUG=True when something fails
  • Hide sensitive information from traceback pages, in case they are ever enabled on purpose or by accident.
  • Avoid enabling DEBUG in production, ever! Reproduce problems on staging always, behind Apache HTTP Auth or similar.

Check Your Redirect URLs

It is really common to have a view like this:

def process_form(request):
    form = SomeForm(request.GET)
    if form.is_valid():
        return HTTPResponseRedirect(request.GET[“redirect_to”])

But, this lets a third party provide users a link which can deceive them.

http://www.your-trusted-site.com/process_form/?foo=1&redirect_to=http://bad-guys-inc.com/

The user will see www.your-trusted-site.com in the link and likely trust the final page they land on as being provided by you, rather than a third party.

Solutions:
  • Check the target URL’s domain before redirecting
  • Make use of django.utils.http.is_safe_url
  • Simply take a path as the redirect URL instead, and combine this with your domain before directing.

Don’t Perform Mutating Actions on GET Requests

It might be very tempting to provide users with a simple link to vote, mark a message as read, or delete a photo.

def vote(request, target_id):
    thing = Thing.objects.get(id=target_id)
    thing.votes += 1
    thing.save()
    return HTTPResponse(“you_voted.html”)

Avoid this pattern, or web crawlers, browser prefetching, or CSRF attacks can become a big problem. You don’t need to do this just to allow a simple link.

def vote(request):
    form = VoteForm(request.POST)
    if form.is_valid():
        thing = form.instance
        thing.votes += 1
        thing.save()
        return HTTPResponse(“You voted!”)
    else:
        return HTTPResponse(“You have to be logged in to vote.”)

and in your HTML, something like

<a herf=”#” onclick=”load(“/vote/”, {target_id: 1})”>Vote!</a>

Cache Leaking

Simple caching is a great way to speed up an expensive function or section of a page, but you can easily omit an important bit of a key and cause a cache entry to leak to users and situations it shouldn’t. Here are some examples.

{% cache site_header %}
<header>
<img src=logo.png>
<span class=tagline>The places where {% total_users %} come to play!</span>
{% cache userbox username %}
<div class=userbox>
    Hi {{ username }}! You have {{ user.messages.count }} messages waiting for you.
</div>
{% endcache %}
</head>
{% endcache %}

You have taken care to cache the userbox portion based on the current username, so that each user will have their own version of the box cached. However, the outer cache tag will store a copy when the first user hits the page and simply reuse this copy for every other user, never even processing the inner cache tag again.

<header>
<img src=logo.png>
{% cache total_users %}
<span class=tagline>The places where {% total_users %} come to play!</span>
{% endcache %}
{% cache userbox username %}
<div class=userbox>
    Hi {{ username }}! You have {{ user.messages.count }} messages waiting for you.
</div>
{% endcache %}
</head>

By avoided nested cache tags and keeping them tightly around the expensive bits, we can avoid this problem.

Or, you could simply use django-better-cache, which makes nested cache tags simply work.