dlint icon indicating copy to clipboard operation
dlint copied to clipboard

Add linter for broken function level authorization

Open mschwager opened this issue 4 years ago • 0 comments

Per the OWASP API Security Top 10, broken function level authorization is a big security concern. Adding a linter to detect this would be very useful. Most Python web application frameworks use decorators on function-level API routes (e.g. rest_framework.decorators.api_view in Django REST framework, flask_login.login_required in Flask-Login).

One way I can envision implementing this would be looking for decorator anomalies in Python files that look like they contain API routes. E.g.

@api.route("/users")
@login_required
def users(request):
    ...

@api.route("/groups")
@login_required
def groups(request):
    ...

@api.route("/settings")
def settings(request):
    # Oops, did we forget @login_required?
    ...

@api.route("/jobs")
@login_required
def jobs(request):
    ...

If XX% of API routes in a file are missing what looks like an authentication decorator, we can flag the function missing the decorator. Another common one for authorization might look something like:

@app.route("/users", roles=[User.Admin])
def users(request):
    ...

@api.route("/groups", roles=[User.Admin])
def groups(request):
    ...

@api.route("/settings", roles=[User.Regular])
def settings(request):
    # Oops, can all users access this sensitive endpoint?
    ...

This may seem trivial, but it gets more difficult as you have many different authentication methods, authorization schemes, and user roles.

This will probably involve some of the following:

  • Looking for common API route decorators and systems used by major Python web frameworks.
  • Using this information to determine if we're in a API route module.
  • Determining what "unusual" looks like in this case (e.g. missing login_required).
  • Performing heuristics, possibly with a configurable threshold, to make the judgement whether a finding is in fact unusual.

There's also some low-hanging fruit here, like just searching for existing "security-off" switches for web framework routes, like:

  • django.views.decorators.csrf.csrf_exempt
  • flask_wtf.csrf.exempt
  • rest_framework.permissions.AllowAny or permission_classes = []
  • Likely many more in well-known third-party packages...

mschwager avatar Mar 19 '20 21:03 mschwager