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

Route-Scoped CORS

CORS permission belongs only on routes intentionally available to other browser origins. Applying it globally can expose authenticated APIs.

Imagine middleware that reflects every origin and allows credentials:

func permissiveCORS(next http.Handler) http.Handler {
    return http.HandlerFunc(func(responseWriter http.ResponseWriter, request *http.Request) {
        if origin := request.Header.Get("Origin"); origin != "" {
            responseWriter.Header().Set("Access-Control-Allow-Origin", origin)
            responseWriter.Header().Set("Access-Control-Allow-Credentials", "true")
        }
        next.ServeHTTP(responseWriter, request)
    })
}

That gives every requesting website permission to read authenticated responses. Scary!

Public and Private APIs

A storefront can have different policies for different routes:

  • A public product catalog may allow credential-free cross-origin reads.
  • Account and order APIs contain authenticated data and don't need cross-origin access.

For a public response, Access-Control-Allow-Origin: * is appropriate because the data needs no credentials. Its preflight response can advertise only GET, without allowing credentials or unnecessary request headers. Authenticated routes should omit CORS permission headers entirely.

Assignment

Bearly Secure grants every requesting origin access to all dynamic APIs. Replace the global policy with CORS limited to the public product API.

  1. go run ./cmd/attackerlab
    

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

You can stop Bearly Evil after submitting the lesson.