Defensive Design & Input Validation
Programs Have to Cope With Real People
When you test your own code, you type exactly what it expects. Real users are less predictable. They leave boxes blank, type letters where a number is needed, paste in a thousand characters, or tap buttons in the wrong order. Defensive design is the habit of writing a program that stays under control no matter what the user throws at it. A program that behaves like this is described as robust.
Getting this wrong is expensive. A program that is not robust can crash and lose the user’s work, store nonsense in a file, or open a security hole that lets an attacker in. Building defences in from the start is far cheaper than patching a broken program later, so professional programmers plan for bad input before they write a single line that trusts it.
Anticipating Misuse
Anticipating misuse means asking, before you write the code, “How might someone break this?” You then make sure each of those situations is handled instead of ignored. Some inputs cause a mistake by accident; others are deliberate attempts to make the program fail.
- Leaving a required field completely empty.
- Typing letters or symbols where a number is expected.
- Entering an impossible value, such as an age of −5 or 300.
- Giving a date that does not exist, like the 31st of February.
- Pasting in an enormous amount of text to try to overload the program.
A well-designed program anticipates each case and responds gracefully. Instead of crashing, it shows a clear, polite message that tells the user what went wrong and how to fix it, then lets them try again. Guarding against a value that would break a calculation — such as dividing by zero — is another example of anticipating misuse.
Input Validation
Input validation is the most important defensive tool. It runs a series of checks on data the moment it is entered, and only lets the data through if it passes. Validation confirms that data is reasonable and allowable; it cannot prove the data is actually true. A validation check will happily accept the wrong-but-sensible age of 21, so validation reduces errors rather than removing them completely.
There are several standard checks, and a single field often uses more than one of them at once.
- A presence check makes sure a required field has not been left empty.
- A range check confirms a number falls between an acceptable lower and upper limit, such as a month between 1 and 12.
- A type check confirms the data is the correct data type, for example a whole number rather than text.
- A length check confirms the data has an acceptable number of characters, such as a password of at least eight.
- A format check confirms the data follows a required pattern, such as an email address containing an “@” symbol.
The five common validation checks are presence, range, type, length and format. Presence rejects an empty box, range rejects a number that is too big or too small, type rejects the wrong data type, length rejects data with the wrong number of characters, and format rejects data that breaks the required pattern.
It is easy to assume that validated data must be correct, but that is not what validation promises. If a user is asked for their year of birth and types 1999 when they were really born in 2000, a range check sees a sensible four-digit year and lets it through. Validation only guarantees that data is possible and allowable, so a robust program still needs sensible defaults, clear instructions and helpful error messages to catch the mistakes that validation cannot see.
Authentication
Authentication protects a program by checking the identity of the person using it. The most common method is a username and password: the username says who you claim to be, and the password proves it because only the real account holder should know it. A program should compare the entered details against stored records and refuse access if they do not match.
Passwords are only useful if they are hard to guess. A strong password is a good length and mixes uppercase and lowercase letters, numbers and symbols, which makes it far harder for an attacker to work out. Many systems add extra layers, such as two-factor authentication — where a password is combined with a second check like a code sent to a phone — along with biometrics such as a fingerprint, or security questions. Each extra layer makes it harder for someone to pretend to be a genuine user.
Every extra character you add to a password multiplies the number of possible combinations an attacker would have to try. A short password made only of lowercase letters can be broken quickly by a computer testing millions of guesses, while a longer password that also uses capitals, digits and symbols has so many combinations that guessing becomes impractical. This is why systems often insist on a minimum length and a mixture of character types — a rule that is enforced using a length check and a format check.
Maintainability
Maintainability is a part of defensive design that is often forgotten. Programs are read, fixed and improved for years, often by a different programmer from the one who wrote them. Code that is tidy and clearly explained can be changed safely; code that is a tangled mess is where new bugs are introduced. Four simple habits make a program much easier to maintain.
First, use sub programs to break a large task into smaller named pieces. This avoids writing the same block of code twice, so if a mistake is found it only has to be fixed in one place. Second, follow sensible naming conventions so that a variable called totalPrice tells the reader exactly what it holds, unlike a vague name such as x.
Third, use consistent indentation so the shape of the code shows its structure — which lines sit inside a loop or a condition. Fourth, add comments to explain anything that is not obvious. A comment is written for the programmer, not the computer, so it never changes what the program does, but it can save hours of confusion later.
Four techniques improve maintainability: using sub programs to avoid repeated code, following clear naming conventions, indenting code to show its structure, and adding comments to explain how it works.