Link Search Menu Expand Document

Broken Authentication in Python

Vulnerable example

The following snippet contains a Flask web application, written in Python, which has an administrative functionality to delete the database when a specific URL is called.

@app.route('/admin/init', methods=['POST'])
def reinitialize():
    cursor.execute("DROP DATABASE analytics")
    return 'Database has been dropped

The /admin/init URI is available to everyone and should be protected by an authentication mechanism so that it can’t be abused by malicious actors.

Prevention

Apply the recommended authentication and authorization mechanisms depending on the web framework of choice.

Django Django uses sessions that provide a request.user attribute which represents the current user. If the current user has not logged in, the attribute is set to AnonymousUser object. The authentication status can be easily checked with User.is_authenticated.

def admin_init(request):
  if request.user.is_authenticated:
      # Do something for authenticated users.
  else:
      # Do something for anonymous users.

Permission can be assigned to users and groups, and it can be validated with User.has_perm().

from django.contrib.auth.models import User
from django.shortcuts import get_object_or_404

def admin_init(request, user_id):
    user = get_object_or_404(User, pk=user_id)
    user.has_perm('myapp.change_database')
    ...

Flask Flask-Session is an extension for Flask that adds support for server-side sessions to a web application.

from flask import Flask, session, abort
from flask.ext.session import Session

app = Flask(__name__)
app.config.from_object(__name__)
Session(app)

@app.route('/admin/init')
def admin_init():
    if not session.get('user', 'is_authenticated')
      abort(401)
    ...

Sanic Sanic-Auth is a Sanic extension that implements a minimal backend agnostic session-based user authentication mechanism.

from sanic_auth import Auth
from sanic import Sanic

app = Sanic(__name__)
app.config.AUTH_LOGIN_ENDPOINT = 'login'
auth = Auth(app)


@app.route('/admin/init')
@auth.login_required(user_keyword='user')
async def initdb(request, user):
  ...

References

https://cwe.mitre.org/data/definitions/285.html https://cwe.mitre.org/data/definitions/287.html https://www.owasp.org/index.php/Testing_for_Bypassing_Authentication_Schema_%28OTG-AUTHN-004%29 http://flask.pocoo.org/ https://www.djangoproject.com/ https://github.com/huge-success/sanic