2.3 - Producing Robust Programs (Part 1)
Defensive Design Considerations
- Defensive design is a set of techniques that can be used to reduce the
likelihood of a program failing in a way that is difficult to detect.
- It considers every possible input from a user and tries to find ways
that the user could break the program.
Key Aspects of Defensive Design:
- Anticipating Misuse: This is probably the most important consideration to make, always assume that someone will try to break the program with malicious intent.
- Input Validation: Ensures that the input received by a program is correct and reasonable before it is processed. This helps avoid errors such as entering unexpected data types, values outside expected ranges, or malicious inputs like SQL injection or script injection.
- Sanitisation: Input sanitisation ensures that any user input is cleaned and prepared correctly to prevent it from causing harm or breaking the system. This is often used to remove or neutralise any malicious content from inputs like form fields or query parameters.
- Authentication and Authorisation: Ensures that users are who they say they are (authentication) and that they have permission to perform certain actions (authorisation). This is crucial for protecting sensitive data and functionality from unauthorised access.
- Preventing Code Injection: Defensive design also involves protecting a program against code injection attacks by ensuring that user inputs are treated safely and are not executed as code.
- Error Handling: Effective error handling ensures that when things do go wrong, the program fails gracefully rather than crashing or exposing sensitive information. This might involve displaying user-friendly error messages or logging the error details for developers to troubleshoot.
- Boundary Testing: Testing the program's behavior at the limits of acceptable input values (e.g., largest and smallest numbers, longest strings) ensures that it can handle edge cases and won't fail unexpectedly in these situations.
Benefits of Defensive Design:
- Improves program reliability by ensuring that potential user mistakes or malicious attempts are managed.
- Reduces the likelihood of program crashes or unpredictable behavior, providing a better user experience.
- Makes code easier to maintain and debug, as errors are caught and handled before they cause bigger problems.
Input Validation
- Input validation is essential for defensive design. It helps
ensure that user input is correct and safe to process, preventing potential
security vulnerabilities and crashes.
- It can prevent attacks such as
SQL injection or cross-site scripting (XSS) attacks, where an attacker can
inject malicious code into the input and potentially execute it on the server.
- It involves checking that the input received by a program is
valid and within the expected range. You can use things such as if statements
to check for banned words, the length of a string, the presence of certain
characters, or the type of data being entered.
SQL Injection Prevention
- SQL injection is a type of attack where an attacker can inject malicious SQL
code into a query, allowing them to manipulate or extract data from the database.
- To prevent SQL injection, you can check your input for statments such as 'DROP table',
and if this is found, either return an error message or simply ensure that the input is
not processed further.
Auth example
Maintainability
- Maintainability is the ability of a program to be easily modified,
extended, and maintained over time.
- It is important for defensive design because it helps prevent errors
and crashes that can occur when making changes to the code.
- Some ways to make code more maintainable include using naming conventions,
the use of sub programs like functions, using comments
to explain the purpose and functionality of different parts of the code,
and using intentation to make the code easier to read.
Example:
Before:
After:
Note that indentation is required in Python, so the first example won't run, but in almost every other language it is optional.