Secure Engineering Guidelines

Some best practices for building and trusting software.

Do Not Trust Input

Never trust anything that comes from the user or client. Always validate or sanitize all input before using it in the application. Common abuses of unchecked user input include:

  • SQL Injection, where untrusted user input is used in raw SQL queries (use parameterized queries).

Minimize Attack Surface

Every interface you accept user input from is attack surface. If you don’t need to take data from the user, don’t!

Architect and Design for Security

Build security into your system from design to deployment, if possible.

Favor Simplicity

The simplest solution is often the correct solution. Simple solutions are easy to understand and explain to other engineers, easy to test, and easy to verify they are implemented correctly.

Principle of Least Privilege

Always grant permissions as required and never over-permission. Try to assume whatever you’re assigning permissions to could be taken control of by an attacker and attempt to give an attacker the least amount of access possible.

If an attacker found an SQL injection vulnerability, it would be best if that application only had read access to the tables it needed to, rather than read and write access to the whole database.

Separation of Duties

Separation of duties is used to limit the risk of unauthorized or unintentional modification of information and systems. Try to assume that an attacker can gain access to at least one component of the system and attempt to make it impossible for an attacker to steal data or compromise the integrity of the system without access to all components.

Defense in Depth

“In a composite system, there is no critical gate: everything is a gate.” — Felix ‘FX’ Lindner

Every access control is an opportunity for an attacker to exploit a system. Equally, every access control is an opportunity for engineers to make a system more robust and secure against attackers. Whenever possible, build defenses in.

Secure Defaults

Default settings, constants, and permissions should always be set to secure values before they are overridden through a secure process.

Secrets Management

Secrets should be stored securely. Passwords, API tokens, and encryption keys should never be committed to source control or stored on an engineer’s machine. Use a secure repository that meets your requirements.

Fail Securely

Always consider the side effects of a system if it were to crash. If a failure were to occur, what state would the system be left in. Always try to catch exceptions and restore the system to a safe state. Consider the example of the Apple goto fail bug.

A failure should never let a user gain unauthorized access. Never assume a user is logged in before they are verified. Never assume a user has permission before it is verified. Never fail open unless you absolutely need to.

Fix Warnings and Errors

As part of general code hygiene, all compiler and runtime errors should be tracked and resolved.

Compiler warnings are typically warnings for a reason. If they aren’t immediately a vulnerability, they may become one. Application runtime errors can leak attackers extra information about the underlying code through stack traces or behavioral leaks. All application exceptions should be handled properly and exception details should never be shown to the user.

General Do Nots

  • Do not trust vendors and third-party services.

Third-Party Libraries

Use these guidelines when determining if a third-party library is secure:

  • Do you trust the library, the author, and their infrastructure? An adtech company might approach the author and ask them to insert a snippet that collects information about your code or your users. A developer could use their library for criminal activity, such as credit card theft or ransomware.

These guidelines are drawn from the following resources:

Thanks to the security team at Flatiron Health who helped solidify these guidelines, including Ben Khakshoor, Chris Sandulow, Nicholas Arvanitis, Darren Gruber, and Justin Berman.

Risk philosopher. CISO. Team and program builder. Ex-vulnerability researcher. Ex-CTF organizer and competitor.