Making a bullet-proof app is probably not feasible, and depending on what your app does, certain security measures might even be overkill.
To make covering the basics easy, here's a set of guidelines that likely apply to your project:
- No secrets in the code
- Use a dependency checker
- Validate user inputs
- No production data in non-prod environments
- Proper access controls
- Enforce HTTPS universally
- Enable logging
We see this more than you'd think. The dangers of leaving secrets into your code are wide ranging and severe. It could lead to everything from an attacker compromising a user's session to full owning your application, and even the application server, gaining access to your database, and impersonating you to uncover more valuable data (and this is not an exhaustive list).
I don't think you need to be scared into not checking secrets in -- you probably already understand that this is bad (maybe), but here are your alternatives:
- Use environment variables (some background; in heroku; in-gocd)
- credstash
- AWS Parameter Store
- If you need to keep the secrets in your code, you can use gitcrypt to encrypt sensitive files on commit.
Using components with known vulnerabilities is a widespread and serious problem in application development. It can lead to easy, scannable vulnerabilities in your app. Recommended tools for a variety of languages are provided elsewhere in this project:
Are you using a tool that isn't in this repo? Are you developing with a language or framework not currently supported? Create an issue or submit a PR so we can get it added as quickly as possible.
If you have fields that accept user input in your application, making it a priority have some validations on this input is imperative to a basic level of security on your application.
An excellent blog post by Cade Cairns and Daniel Somerfield outlines some of the dangers of accepting as-is user input, along with some mitigation strategies.
Here are some of the main takeaways:
- Accepting unvalidated input can lead to an attacker taking control of the app itself.
- Setup alerts for potential attacks.
- Whitelist (positive validation) expected inputs over blacklisting a set of known unwanted inputs (negative validation). Make your whitelist strict.
- "Resist the temptation to filter out invalid input" aka "sanitization". Reject invalid input altogether.
In a similar vein (and in the same blog post), take care to encode HTML output as well.
Dev, QA, and staging environments (and their equivalents) often do not have the same care and security measures that are applied to a production environment. Additionally, this is where we do our testing -- where we break things and elicit unexpected behavior.
Real Data in App Testing Poses Real Risks
The Security Threat From Within
This one is tricky as it is very dependent on the context of your application. Here are some things to consider:
- How do users authenticate? Are you using a secure library?
- Should only privileged users have access to certain resources? Where are these roles stored? Could they be manipulated by user input?
- What systems/services can access your database?
This last point is absolutely critical. App context varies, but an anonymous user/system/service should never be able to access your database. Make sure there is a strong authentication model for your database.
More Resources:
You get this one! I know it. I know it. It's 2018, and we don't need convincing, right?
But did you know your application could still be vulnerable to a MiTM attack if it isn't using HSTS?
Logs can help you detect and respond to potential malicious behavior in your application.