Skip to content
The library

Notes on a book

Designing Secure Software

Loren Kohnfelder · No Starch Press, 2021

A guide to threat modelling and secure design from the engineer who co-invented the certificate. Ten of ctfpal's modules cite it, because every crypto challenge is a design decision somebody made wrongly.

Kohnfelder is the person who, as a student in 1978, wrote the thesis that put public keys inside signed certificates, and later co-authored the STRIDE threat taxonomy at Microsoft. This book is what four decades of that looks like written down for developers: not a catalogue of attacks, but an account of how to design something so that the attacks do not have anywhere to land.

That makes it an odd entry on a capture-the-flag shelf, and it is the most cited book in the whole curriculum anyway. The reason is simple. A CTF challenge is almost never a broken algorithm. It is a correct algorithm wired up by somebody who did not know what it promised - a nonce reused, a digest checked for the wrong property, an input trusted one layer too deep. This book is where those promises are written out plainly, which is what lets you name the one that got broken.

Why it is on this shelf

Most security books are organised by attack. This one is organised by decision: trust boundaries, the mitigation you pick, the design pattern and its anti-pattern. Read as an attacker, that inverts usefully - a chapter that tells a developer the six things a design must get right is a six-item checklist of what to test.

Chapter 5, Cryptography

The chapter every cryptography module in the curriculum points at, and the reason it works for that is that it deliberately refuses to do the mathematics. Kohnfelder calls it the driver's-ed level: how to use the toolbox, not how the engine is machined. The toolbox is seven items, and each is introduced together with the single property its security rests on.

  • Random numbers, useful as padding and nonces, but only if unpredictable.
  • Message digests, a fingerprint of data, but only if collisions are out of reach.
  • Symmetric encryption, concealing data behind a secret both parties hold.
  • Asymmetric encryption, concealing data behind a secret only the recipient holds.
  • Digital signatures, authenticating data behind a secret only the signer holds.
  • Digital certificates, authenticating signers behind trust in a root.
  • Key exchange, agreeing a shared secret across a channel somebody is listening to.

Write those seven lines out and you have a diagnostic. Every crypto challenge in this curriculum is one of them with its stated condition removed. Predicting a PRNG is line one without unpredictability. Length extension is line two used as though it were a signature. Nonce reuse in AES-GCM is line three with the padding-and-nonces caveat ignored. Common modulus and Hastad are line four with the secret shared across recipients.

The chapter is also unusually good on the distinction that trips people up in hash challenges: preimage, second preimage and collision are three different promises, and "this hash is broken" almost always means only the third one. MD5 collides on demand and is still preimage-resistant, which is exactly why a collision challenge and a cracking challenge look nothing alike.

One passage worth reading slowly is the PRNG example. He prints a sixty-digit sequence, points out that its digit distribution is unremarkable, and then reveals it is pi from the two-hundredth decimal. Statistically random, completely predictable. That gap is the entire subject of the PRNG tools here, and it is why a chi-squared test on a keystream tells you much less than people assume.

Chapter 6, Secure Design

This is the chapter about writing the design down: functional description, technical specification, and a background section that states the assumptions out loud. His argument is that unwritten assumptions are where interfaces mismatch and attackers live. The anecdote he tells is a hardware team from IBM and a software team from HP shipping a machine where "bit 0" meant opposite ends of the word, because nobody thought endianness needed saying.

For an attacker the takeaway is the list of assumptions he tells designers to document, read backwards. Whether the system expects to be a target. What data it considers sensitive. What legacy compatibility it is non-negotiably carrying. In an application-logic challenge that last one is usually the answer: the endpoint that still accepts the old parameter, the format kept alive for a client nobody uses. That is the ground reading a design for flaws works over, and it is the reason API logic challenges reward reading the documentation before the traffic.

Chapter 10, Untrusted Input

The longest and most directly usable chapter in the book. His definition is worth stealing verbatim: untrusted inputs are not inputs you mistakenly trust, they are inputs you should not trust. The chapter then walks the injection classes as one family - SQL, path traversal, regular expressions, XML external entities - because they are one family: data crossing a boundary into a context that parses it.

The part with the most carry-over is the treatment of validation as a range-narrowing operation rather than a filter. Validation that decides what is valid is robust; validation that decides what is dangerous is a blocklist, and a blocklist is a puzzle with a solution. That is the whole of SQL injection in CTF and most of path traversal and LFI: find the thing the author thought was dangerous, then find the encoding of your payload that is not it.

His Unicode section is the one people skip and should not. Normalisation happens after validation more often than before it, and a canonicalisation that runs on the far side of the check is a bypass by construction - the same defect Hunting Security Bugs gives a whole chapter to.

Where it stops

This is a design book, and it will not teach you to attack anything. There are no payloads in it, no tooling, and no worked exploits. The crypto chapter names the primitives and their properties and then quite deliberately stops before the mathematics, so it will not get you through an RSA challenge on its own - for that you want the decision tree and the parameter checks it drives.

It is also a book about systems being built, which is not the situation you are in during a competition. Read it for the vocabulary and the promises, not for a method.

What to take into a challenge

One habit, and it survives contact with almost every crypto and web category: before you attack, name the property the design was relying on. Confidentiality, integrity, authenticity, unpredictability, freshness. Then ask which one the artefact in front of you fails to establish. A ciphertext that you can modify without detection is not a confidentiality problem, it is a missing MAC, and knowing that is the difference between guessing at a padding oracle and going straight to a bit-flip.