# Lesson 9 — Rate Limiting & Security Hardening > **New Go concepts in this lesson:** almost none new at the language > level — this lesson is mostly about correctly configuring existing > tools (`httprate`, `cors`, cookie flags) rather than new syntax. A good > lesson to consolidate everything from Go Basics so far. Four separate concerns, each small on its own: **rate limiting** (stop abuse/brute-force), **secure cookie flags** (protect the session cookie itself), **CORS** (control which websites can call your API from a browser), and a basic **CSRF** mitigation for our cookie-based sessions. ## Part A — standalone playgrounds ### 1. Rate limiting with `httprate` ```bash mkdir ~/go-playground/security-demo && cd ~/go-playground/security-demo go mod init security-demo go get github.com/go-chi/httprate@latest go get github.com/go-chi/chi/v5@latest ``` **`main.go`** ```go package main import ( "fmt" "log" "net/http" "time" "github.com/go-chi/chi/v5" "github.com/go-chi/httprate" ) func main() { r := chi.NewRouter() // 1. Limit EVERY client to 5 requests per 10 seconds, keyed by IP. r.Use(httprate.LimitByIP(5, 10*time.Second)) r.Get("/ping", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "pong") }) log.Println("listening on :4000") log.Fatal(http.ListenAndServe(":4000", r)) } ``` Run it and hammer it: ```bash go run . for i in $(seq 1 8); do curl -s -o /dev/null -w "%{http_code}\n" http://localhost:4000/ping; done ``` You should see `200` five times, then `429` (Too Many Requests) for the rest, until 10 seconds pass. - `httprate.LimitByIP(5, 10*time.Second)` — a ready-made middleware (same `func(http.Handler) http.Handler` shape you already know) tracking request counts **per client IP**, in a sliding window. Exceeding the limit auto-responds with `429 Too Many Requests` — you don't write that logic yourself. - Why keyed by IP: without a key, one abusive client could exhaust the "budget" for every other user too. `LimitByIP` isolates each caller's own quota. (Other keying strategies exist too — `LimitByRealIP`, or custom keys like "by user ID" once authenticated.) This matters most on `/login` and `/register` — without it, someone could script thousands of password guesses per second against `/login`. ### 2. Cookie security flags No need to run this one — just understand each flag, since we set these on `scs`'s cookie config (already partly done in Lesson 6), not by hand: ```go http.SetCookie(w, &http.Cookie{ Name: "session_id", Value: "abc123", Path: "/", HttpOnly: true, // JS cannot read this cookie Secure: true, // browser only sends it over HTTPS SameSite: http.SameSiteLaxMode, // restricts cross-site sending }) ``` - `HttpOnly: true` — blocks `document.cookie` access from JavaScript. Defeats a whole class of XSS attacks that try to steal the session cookie via injected script. - `Secure: true` — the browser will refuse to send this cookie over plain HTTP, only HTTPS. **Important gotcha**: if you set this while developing locally over `http://localhost`, the cookie won't be sent at all — you'll be confused why sessions "don't work." We'll make this environment-dependent in Part B. - `SameSite: http.SameSiteLaxMode` — controls whether the cookie is sent on cross-site requests. `Lax` (a good default) sends the cookie on top-level navigations (clicking a link to your site) but not on cross-site `POST`s triggered by another page (like a malicious `