We're sorry but this app doesn't work properly without JavaScript enabled. Please enable it to continue.

This lesson's interactive features are locked, please to keep using them

Preventing Broken Access Control

Authentication answers the question, "Who are you?" Authorization answers "What are you allowed to do?"

Broken access control happens when the server forgets to ask that second question. It's usually a careless mistake, not some clever Linux-kernel exploit:

  • A route checks that you're logged in, but not what you can access.
  • A route trusts a role specified by the client.
  • A route uses an ID provided in the URL, but never verifies the user owns that resource.

The Rule of Thumb

Every protected action needs a server-side permission check. Not in the UI. Not in the mobile app. Not in a hidden form field. On the server. On every request.

A secure endpoint does two things, in order:

This endpoint has a problem:

document, found, err := store.FindByID(request.Context(), documentID)
if err != nil {
  return err
}
if !found {
  respondNotFound(responseWriter)
  return nil
}
respondWithJSON(responseWriter, document)

It checks that the user is logged in, but it lets any logged-in user see any document just by changing the ID in the URL!

To fix it, compare the document's owner with the authenticated user. If the document belongs to another user, return a 404 Not Found response:

document, found, err := store.FindByID(request.Context(), documentID)
if err != nil {
  return err
}
if !found || document.UserID != current.User.ID {
  respondNotFound(responseWriter)
  return nil
}
respondWithJSON(responseWriter, document)

Returning the same 404 Not Found response for missing and unauthorized documents also avoids confirming that another user's document exists. A 403 Forbidden response is fine when it's not sensitive that a resource exists, but a 404 reveals even less here.

How Attackers Find These Bugs

Attackers don't need clever exploits. They try the obvious things and see what the server lets through:

  • Calling endpoints directly
  • Changing IDs in the URL
  • Repeating requests with small variations

If the server doesn't enforce permissions, an attacker will eventually find something that works.

Assignment

The order-detail route returns any order whose ID appears in the URL. Enforce order ownership on the server.

  1. go run ./cmd/seed
    go run ./cmd/server
    

With Bearly Secure still running, run and submit the CLI tests from the project root.