Cross Site Request Forgery in Gorilla Mux with Cockroachdb
Cross Site Request Forgery in Gorilla Mux with Cockroachdb — how this specific combination creates or exposes the vulnerability
Cross Site Request Forgery (CSRF) occurs when an authenticated endpoint relies only on cookies for session handling and does not validate the request origin or intent. When you use Gorilla Mux to route HTTP requests to services that read from or write to Cockroachdb, CSRF risk arises if handlers do not enforce anti-CSRF controls. Because Cockroachdb is often used in production services that manage sensitive user or financial data, an attacker who can trick a logged-in user into submitting a crafted request may perform unauthorized actions that directly affect your Cockroachdb-backed tables.
Gorilla Mux does not provide built-in CSRF protection; it is a router that matches incoming requests to handler functions. If your handlers parse session identifiers from cookies and then execute SQL against Cockroachdb without verifying the request source, you expose an attack surface. For example, a banking-style handler that uses the session cookie to identify the user and issues a Cockroachdb UPDATE to change email or transfer funds is vulnerable if it lacks a synchronizer token or SameSite cookie policy. An attacker can host a malicious page that submits a form or fetches an image URL pointing to your endpoint, leveraging the victim’s existing Cockroachdb session to perform state-changing operations.
Common patterns that increase risk include:
- Using cookie-based sessions without CSRF tokens for state-changing HTTP methods (POST, PUT, DELETE).
- Exposing admin or write endpoints under routes handled by Gorilla Mux without checking the Origin or Referer header.
- Relying on the browser to send credentials automatically to your domain while your Cockroachdb queries do not validate intent.
Because Cockroachdb supports distributed transactions, an attacker’s forged request might span multiple statements, making the impact more severe. Therefore, it is essential to treat routing and database interaction together: secure the HTTP layer with CSRF defenses and ensure your Cockroachdb access patterns do not implicitly trust cookie-bound sessions alone.
Cockroachdb-Specific Remediation in Gorilla Mux — concrete code fixes
Remediation focuses on ensuring every request that changes data includes an explicit, verifiable token or header, and that session handling is hardened. Below are concrete, idiomatic examples for Gorilla Mux handlers that interact with Cockroachdb.
1. Use SameSite and Secure cookies for session handling
http.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.SetCookie(w, &http.Cookie{
Name: "session_id",
Value: generateSessionID(),
HttpOnly: true,
Secure: true,
SameSite: http.SameSiteStrictMode,
Path: "/",
})
}))
2. Validate the Origin header on state-changing requests
func requireOrigin(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
origin := r.Header.Get("Origin")
if origin != "https://your-app.example.com" {
http.Error(w, "Forbidden", http.StatusForbidden)
return
}
next.ServeHTTP(w, r)
})
}
r := mux.NewRouter()
r.Handle("/transfer", requireOrigin(http.HandlerFunc(transferHandler))).Methods("POST")
3. Implement per-request CSRF tokens and validate them before Cockroachdb writes
func csrfToken(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := r.FormValue("csrf_token")
sessionID, err := r.Cookie("session_id")
if err != nil || token != generateCSRFToken(sessionID.Value) {
http.Error(w, "Invalid CSRF token", http.StatusForbidden)
return
}
next.ServeHTTP(w, r)
})
}
func transferHandler(w http.ResponseWriter, r *http.Request) {
db, err := sql.Open("postgresql", "postgresql://user:pass@host:26257/db?sslmode=require")
if err != nil {
http.Error(w, "Internal error", http.StatusInternalServerError)
return
}
defer db.Close()
from := r.FormValue("from")
to := r.FormValue("to")
amount := r.FormValue("amount")
tx, err := db.BeginTx(r.Context, nil)
if err != nil {
http.Error(w, "Internal error", http.StatusInternalServerError)
return
}
defer tx.Rollback()
_, err = tx.ExecContext(r.Context, "UPDATE accounts SET balance = balance - $1 WHERE user_id = $2", amount, from)
if err != nil {
http.Error(w, "Failed to debit", http.StatusInternalServerError)
return
}
_, err = tx.ExecContext(r.Context, "UPDATE accounts SET balance = balance + $1 WHERE user_id = $2", amount, to)
if err != nil {
http.Error(w, "Failed to credit", http.StatusInternalServerError)
return
}
if err := tx.Commit(); err != nil { // COMMIT will also retry on contention in Cockroachdb
http.Error(w, "Commit failed", http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
w.Write([]byte("Transfer succeeded"))
}
r := mux.NewRouter()
r.Handle("/transfer", csrfToken(http.HandlerFunc(transferHandler))).Methods("POST")
4. Use context timeouts and retries for Cockroachdb operations
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
defer cancel()
err := db.PingContext(ctx)
if err != nil {
http.Error(w, "Database unavailable", http.StatusServiceUnavailable)
return
}
By combining secure cookie attributes, explicit origin validation, and per-request CSRF tokens with properly committed Cockroachdb transactions, you reduce the risk that an attacker can exploit a forged request to mutate data.