Grokking Web Application Security: Chapter-by-Chapter Notes
I’ve been meaning to tighten up my web app security fundamentals for a while, and this book felt like the right kind of structured pass. Not a random blog rabbit hole. Not a certification grind. Just a direct, readable walk through the things that actually break real apps. I’m writing this breakdown mostly for me, but if it helps anyone else, even better.
This is still intentionally short and neutral, but I added a bit more depth and a few tiny examples. Think of it like a table-of-contents map with a couple sentences of why each chapter matters and a few concrete anchors.
Part 1
1. Know your enemy
Sets the stage for the threat landscape, motivations, and the general shape of modern attacks. It frames the rest of the book around practicality: what gets targeted, how often, and what the fallout looks like. The main takeaway is that security is not a one-off decision, it is a continuous response to real incentives and real adversaries.
Go example (basic security headers as a baseline):
func securityHeaders(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-Frame-Options", "DENY")
w.Header().Set("X-Content-Type-Options", "nosniff")
w.Header().Set("Referrer-Policy", "strict-origin-when-cross-origin")
next.ServeHTTP(w, r)
})
}
2. Browser security
Walks through browser architecture and the built-in constraints that keep users safe. The chapter puts the JavaScript sandbox, storage, and cookies into concrete security context. The details here explain why some browser behaviors feel annoying until you see the threat model behind them.
Go example (CSP header):
func csp(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Security-Policy", "default-src 'self'; script-src 'self'")
next.ServeHTTP(w, r)
})
}
3. Encryption
Gives a clear overview of encryption basics and how it shows up in web apps. It covers keys, data in transit vs. at rest, and why integrity checks matter in practice. It also keeps a nice boundary between what the app developer configures and what the infrastructure should enforce.
Go example (enforce HTTPS and HSTS):
func enforceTLS(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Strict-Transport-Security", "max-age=63072000; includeSubDomains")
if r.TLS == nil {
http.Redirect(w, r, "https://"+r.Host+r.URL.String(), http.StatusMovedPermanently)
return
}
next.ServeHTTP(w, r)
})
}
4. Web server security
Focuses on the core defensive layers: validating input, escaping output, and guarding resources. It also reinforces defense-in-depth and least-privilege as non-negotiables. The key idea here is that input handling and output encoding are not optional if your app renders user data anywhere.
Go example (validate UUID + escape HTML):
var uuidRe = regexp.MustCompile(`^[a-f0-9-]{36}$`)
func userHandler(w http.ResponseWriter, r *http.Request) {
id := r.URL.Query().Get("id")
if !uuidRe.MatchString(id) {
http.Error(w, "invalid id", http.StatusBadRequest)
return
}
tmpl := template.Must(template.New("user").Parse("Hello, {{.}}"))
_ = tmpl.Execute(w, id)
}
Unsafe anti-pattern (string concat into HTML):
fmt.Fprintf(w, "Hello, %s", r.URL.Query().Get("name"))
5. Security as a process
Shifts from tactics to workflow. It covers review habits, automation, audits, and the reality that secure code is as much process as it is implementation. The framing is basically: good intentions do not scale, systems and checklists do.
Go example (dependency scanning with govulncheck):
govulncheck ./...
Part 2
6. Browser vulnerabilities
Covers the classic client-side pitfalls: XSS, CSRF, clickjacking, and script inclusion. This is the reminder that a lot of browser security comes down to what your app allows into the page. You do not need a fancy exploit when the DOM is already wired to trust user-controlled strings.
Go example (CSRF token pattern, simplified):
func setCSRFCookie(w http.ResponseWriter, token string) {
http.SetCookie(w, &http.Cookie{
Name: "csrf_token",
Value: token,
Path: "/",
HttpOnly: true,
Secure: true,
SameSite: http.SameSiteLaxMode,
})
}
7. Network vulnerabilities
Focuses on attacks in the wire: MITM, misdirection, cert compromise, and stolen keys. It reinforces why transport security is table stakes and not a one-time setup. The chapter ties together DNS, TLS, and cert hygiene so the chain is only as strong as its weakest link.
Go example (TLS config with modern minimums):
server := &http.Server{
Addr: ":443",
TLSConfig: &tls.Config{
MinVersion: tls.VersionTLS12,
},
}
8. Authentication vulnerabilities
Explores where logins break in real life: brute force, weak storage, SSO edge cases, and user enumeration. It also covers hardening options like MFA and biometrics. The focus is on preventing guessability and reducing the blast radius when credentials inevitably leak.
Go example (password hashing with bcrypt):
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return err
}
Unsafe anti-pattern (storing plaintext passwords):
INSERT INTO users(email, password) VALUES(?, ?)
9. Session vulnerabilities
Breaks down session mechanics and how they get hijacked or tampered with. A good reminder that sessions are security boundaries, not just a convenience. This is also where cookie flags and rotation policies matter more than most teams expect.
Example (session cookie flags, simplified):
Set-Cookie: session_id=...; HttpOnly; Secure; SameSite=Lax
Go example (session cookie):
http.SetCookie(w, &http.Cookie{
Name: "session_id",
Value: sessionID,
Path: "/",
HttpOnly: true,
Secure: true,
SameSite: http.SameSiteLaxMode,
})
10. Authorization vulnerabilities
Focuses on modeling and enforcing access control, not just authentication. The emphasis is on design-time clarity and testing the permissions you think you have. The theme here is that authz bugs are often a missing rule, not a broken feature.
Go example (explicit authorization check):
func canView(user User, resource Resource) bool {
return user.ID == resource.OwnerID || user.IsAdmin
}
11. Payload vulnerabilities
Covers the less glamorous but very real parsing and upload issues: deserialization, XML, files, traversal, and mass assignment. It frames payloads as a major attack surface, not a niche concern. The chapter is a reminder that file handling and parsing are security-critical code paths.
Go example (file upload size limit + content-type check):
r.Body = http.MaxBytesReader(w, r.Body, 10<<20)
file, header, err := r.FormFile("upload")
if err != nil {
http.Error(w, "bad upload", http.StatusBadRequest)
return
}
defer file.Close()
if !strings.HasPrefix(header.Header.Get("Content-Type"), "image/") {
http.Error(w, "unsupported type", http.StatusBadRequest)
return
}
12. Injection vulnerabilities
The classic injection tour: SQL, NoSQL, LDAP, command, CRLF, and regex. It keeps the focus on how user input becomes execution and why that path must be locked down. The central idea is that the safest API is the one that never builds strings for interpreters.
Example (parameterized query, simplified):
SELECT * FROM users WHERE id = ?
Go example (parameterized query):
row := db.QueryRowContext(ctx, "SELECT id, email FROM users WHERE id = ?", id)
Unsafe anti-pattern (string building):
q := "SELECT id, email FROM users WHERE id = " + id
13. Vulnerabilities in third-party code
Zooms out to supply chain risks and dependency management. It also covers leaks and insecure configs that ride in with vendors or libraries. The framing is about ownership: if you ship it, you own its security posture.
Go example (pinning module versions in go.mod):
require golang.org/x/crypto v0.27.0
14. Being an unwitting accomplice
Focuses on attacks that turn your app into someone else’s weapon: SSRF, email spoofing, and open redirects. The key idea is that harm can happen even when the target isn’t you. The pattern is usually a helpful feature that trusts untrusted inputs.
Go example (simple allowlist check):
allowed := map[string]bool{"api.example.com": true}
u, _ := url.Parse(target)
if !allowed[u.Hostname()] {
return errors.New("blocked host")
}
15. What to do when you get hacked
Ends with incident response: detection, containment, analysis, and communication. The theme is that recovery is as much about process and transparency as it is about patching. You are buying time and clarity under pressure, which is its own skill set.
Go example (structured logging for incident response):
log.Printf("event=auth_failure user_id=%s ip=%s", userID, r.RemoteAddr)
Fin
This is the kind of book I can keep around and dip into when a specific issue shows up on a real project. The chapter coverage is broad, but the framing keeps it grounded in how modern web apps actually fail. If you’re building or maintaining web apps, having this mental map is worth the time.
Grokking Web Application Security (Manning)