Checklists have been proven to work, but the software I write (low-level high-security/crypto software) is less repetitive than (most) surgeries. I haven't managed to use anything checklist-like while writing code; however, quickly pattern-matching against a mental library has been exceedingly useful when _reviewing_ code.
Here are some sources I would recommend to people building their own mental checklists:
- The Art of Software Security Assessment (thanks to tptacek); I actually learnt most of this from bits 'n pieces scattered over the web, but it's a very convenient collection;
- Common crypto flaws. Always look for authentication, _then_ encryption, _and_ replay protection. (The latter is often forgotten even in otherwise good protocols.) If a password is used anywhere, consider bruteforcing it (bcrypt may stop such attacks - or not.) Check that IVs are used as demanded by the mode (in particular, that CTR or GCM IVs are not reused.) Look for timing attacks; the easy-to-spot and high-impact ones are use of memcmp() with HMACs and use of CBC on unauthenticated data (padding oracle).
- Buffer overflows may be bad, but integer under-/overflows are much more common (in decent code.) Basically, you need a check before any operation involving a user-supplied length, and this is very commonly forgotten. (Using functions with internal overflow checking, like a decent calloc, helps.)
- Consider the wider context. Spotting a buffer overflow is easy. Noting that you forgot to <? include auth.php ?> is harder. You likely won't notice that the latest "cleanup" leaves the firmware updater open to the internet unless you actually spend five seconds thinking about the wider system.
(I'm quite interested in other's tips; the above is clearly very slanted. Also, I feel vaguely guilty about doing all of this in memory instead of from a paper checklist - does anyone have positive or other experiences with those?)
Comments
Checklists have been proven to work, but the software I write (low-level high-security/crypto software) is less repetitive than (most) surgeries. I haven't managed to use anything checklist-like while writing code; however, quickly pattern-matching against a mental library has been exceedingly useful when _reviewing_ code.
Here are some sources I would recommend to people building their own mental checklists:
- The Art of Software Security Assessment (thanks to tptacek); I actually learnt most of this from bits 'n pieces scattered over the web, but it's a very convenient collection;
- Common crypto flaws. Always look for authentication, _then_ encryption, _and_ replay protection. (The latter is often forgotten even in otherwise good protocols.) If a password is used anywhere, consider bruteforcing it (bcrypt may stop such attacks - or not.) Check that IVs are used as demanded by the mode (in particular, that CTR or GCM IVs are not reused.) Look for timing attacks; the easy-to-spot and high-impact ones are use of memcmp() with HMACs and use of CBC on unauthenticated data (padding oracle).
- Buffer overflows may be bad, but integer under-/overflows are much more common (in decent code.) Basically, you need a check before any operation involving a user-supplied length, and this is very commonly forgotten. (Using functions with internal overflow checking, like a decent calloc, helps.)
- Consider the wider context. Spotting a buffer overflow is easy. Noting that you forgot to <? include auth.php ?> is harder. You likely won't notice that the latest "cleanup" leaves the firmware updater open to the internet unless you actually spend five seconds thinking about the wider system.
(I'm quite interested in other's tips; the above is clearly very slanted. Also, I feel vaguely guilty about doing all of this in memory instead of from a paper checklist - does anyone have positive or other experiences with those?)