Pushing Left, Like a Boss — Part 5.9 — Error Handling and Logging
All errors should be caught and handled gracefully; there should never be a stack trace or database error on the screen. Not only so that we look like professionals, but so that attackers are not given extra information to use against us when creating their attacks. When errors happen, an application should never fail into an unknown state, it should always roll back any transaction it was performing, and ‘close’ anything it may have opened. Such a situation should also always be logged, so that if an incident were to arise incident responders would have something to work with when they investigate, and so that auditors can verify that the system is and has been working correctly.
- All application errors must be ‘caught’ and handled, they can never be left ‘unhandled’.
- Having a catch-all mechanism (global exception handling) is highly advisable, to ensure unexpected errors are always handled properly.
- Internal information, stack traces or other crash information should never be revealed to the user or potential attackers.
- Error messages should reveal as little as possible. Ensure they do not “leak” information, such as details about the server version or patching levels.
- Do not reveal if it is the username or password that is incorrect if there is a login error, as this allows for username enumeration.
- Always “fail safe” or “fail closed”, do not “fail open” or to an unknown state. If an error occurs, do not grant access or complete the transaction, always roll back.
- Security-related errors (repeated login fails, access control failures, repeated server-side input validation failures) should issue a system alert. Ideally, log files will feed into an intrusion prevention/detection system or an application SIEM. This can be tested by running a vulnerability scanner against your application, it should cause events that trigger logging.
- System logs must not contain sensitive information.
- Login fails and other login-related errors should be logged.
- Brute force attempts should be logged (defined here as 10 or more successive failed attempts to login, in under 1 minute, or 100 or more failed attempts in one 24 hour period).
- All security related events. Examples: a user being authenticated, a user being locked out after several failed login attempts, an unaccounted-for error, anything the global exception handler catches, input validation errors.
- what type of event occurred (why this event is security-related/name for event),
- when the event occurred (timestamp),
- where the event occurred (URL),
- the source of the event (IP address), **
- the outcome of the event, and
- (if possible) the identity of any individuals, users or subjects associated with the event.
** If the IP comes from X-Forwarded-For header do not forget to properly validate it, as it could have been tampered with. Special thanks to Dominique Righetto for this point! **
You can, of course, log more than what is listed here.
- Log files and audit trails must be protected, even the backups.
- Ideally logs are all saved into the same space, in the same format, to be easily consumable by a SIEM or other security tools.
- Only authorized individuals should have access to logs.
- Logs should be stored in an encrypted format.
- Logs should be accessible by your incident response team.
- Logs should be stored on a secure server or other secure area.
- Log files must be incorporated into your organization’s overall backup strategy.
- Log files and media must be deleted and disposed of in the same way you would dispose of any sensitive information.
For more information on this topic the new OWASP Top Ten (2017, Item #10) contains detailed advice on this topic.
Reminder; never log Personally Identifiable Information (PII) or anything else sensitive such as SIN, passwords, or dates of birth.
For more detailed information on this and so many other application security related topics please check out the extremely helpful “OWASP Cheat Sheets” project.