Developing secure, robust web applications in the cloud is hard, very hard. If you think it is easy, you are either a higher form of life or you have a painful awakening ahead of you.
If you have drunk the MVP cool-aid and believe that you can create a product in one month that is both valuable and secure — think twice before you launch your “proto-product”.
After you review the checklist below, acknowledge that you are skipping many of these critical security issues. At the very minimum, be honest with your potential users and let them know that you don’t have a complete product yet and are offering a prototype without full security.
This checklist is simple, and by no means complete. I’ve been developing secure web applications for over 14 years and this list contains some of the more important issues that I’ve painfully learned over this period. I hope you will consider them seriously when creating a web application.
This is version 2 of the checklist. It has been re-organized from Version 1 and has a few new items by public demand (Thank you). While I try to keep the list tight and focussed, please comment if you have an item that you think I should add to the list.
Credentials and Secrets
[ ] Store and distribute secrets using a key store designed for the purpose. Don’t hard code secrets in your applications and definitely don't store in GitHub!. For CMS fans, don't store your credentials in a file in the document directory.
[ ] Use a team-based password manager such as 1Password for all service passwords and credentials. NEVER email passwords or credentials to team members.
[ ] Use multi-factor authentication for all your logins to service providers.
Authentication
[ ] Ensure all passwords are hashed using appropriate crypto such as bcrypt. Never write your own crypto and correctly initialize crypto with good random data. Consider using an authentication service like Auth0 or AWS Cognito.
[ ] Use best-practices and proven components for login, forgot password and other password reset. Don’t invent your own — it is hard to get it right in all scenarios.
[ ] Implement simple but adequate password rules that encourage users to have long, random passwords.
[ ] Never, EVER have any undocumented and unpublicized means of access to the device including back-door accounts (like "field-service").
[ ] Run applications and containers with minimal privilege and never as root (Note: Docker runs apps as root by default).
Database
[ ] Don't store sensitive data unless you truly need it. This means email addresses, personally identifying information and other personal information in general. Treat sensitive data like radioactive waste — i.e. there is an real, large and ongoing cost to securing it, and one day it can hurt you.
[ ] Keep a complete list of all the places you store sensitive information: databases, file systems, Dropbox, GitHub, Vault, Office docs and even the paper folder. This is useful to manage, required by GDPR and essential if hacked. You need to be able to locate all sensitive information.
[ ] If subject to GDPR, make sure you really understand the requirements and design it in from the start. For some, it will represent a major change in design and thinking. See and Intro to GDPR.
[ ] Use encryption for data identifying users and sensitive data like access tokens, email addresses or billing details if possible (this will restrict queries to exact match lookups).
[ ] If your database supports low cost encryption at rest (like AWS Aurora), then enable that to secure data on disk. Make sure all backups are stored encrypted as well.
[ ] Use minimal privilege for the database access user account. Don’t use the database root account and check for unused accounts and accounts with bad passwords.
[ ] Fully prevent SQL injection by only using SQL prepared statements. For example: if using NPM, don’t use npm-mysql, use npm-mysql2 which supports prepared statements.
Apps
[ ] Secure development systems with equal vigilance to what you use for production systems. Build the software from secured, isolated development systems.
[ ] Ensure that all components of your software are scanned for vulnerabilities for every version pushed to production. This means O/S, libraries and packages. This should be automated into the CI-CD process.
[ ] Do client-side input validation for quick user feedback, but never trust it. Always validate and encode user input before displaying.
[ ] Validate every last bit of user input using white lists on the server. Consider generating validation code from API specifications using a tool like Swagger, it is more reliable than hand-generated code.
[ ] Never directly inject user content into responses. Never use untrusted user input in SQL statements or other server-side logic.
[ ] Use centralized logging for all apps, servers and services. You should never need SSH to access or retrieve logs.
[ ] Log with sufficient detail to diagnose all operational and security issues and NEVER log sensitive or personal information. Consider creating logs in JSON with high cardinality fields rather than flat text lines.
[ ] Don't emit revealing error details or stack traces to users and don't deploy your apps to production with DEBUG enabled.
APIs
[ ] Ensure that users are fully authenticated and authorized appropriately when using your APIs.
[ ] Ensure that no resources are enumerable in your public APIs. For IDs, consider using RFC 4122 compliant UUIDs instead of integers. For node, see NPM uuid.
[ ] Use canary checks in APIs to detect illegal or abnormal requests that indicate attacks.
Network Traffic
[ ] Segment your network and protect sensitive services. Use firewalls, virtual private networks and cloud Security Groups to restrict and control inbound and outbound traffic to/from appropriate destinations. AWS and CloudFlare both have excellent offerings.
[ ] Use TLS for the entire site, not just login forms and responses. Never use TLS for just the login form. Transitionally, use the strict-transport-security header to force HTTPS on all requests.
[ ] Cookies must be httpOnly and secure and be scoped by path and domain.
[ ] Use CSP without allowing unsafe-* backdoors. It is a pain to configure, but worthwhile. Use CSP Subresource Integrity for CDN content.
[ ] Use X-Frame-Option, X-XSS-Protection headers in client responses. Use https://observatory.mozilla.org to score your site.
[ ] Use HSTS responses to force TLS only access. Redirect all HTTP request to HTTPS on the server as backup.
[ ] Use CSRF tokens in all forms and use the new SameSite Cookie response header which fixes CSRF once and for all newer browsers.
[ ] Remove other identifying headers that can make a hackers job easier of identifying your stack and software versions.
[ ] Don't use GET requests with sensitive data or tokens in the URL as these will be logged on servers and proxies.
Cloud Configuration
[ ] Ensure all services have minimum ports open. While security through obscurity is no protection, using non-standard ports will make it a little bit harder for attackers.
[ ] Host backend database and services on private VPCs that are not visible on any public network. Be very careful when configuring AWS security groups and peering VPCs which can inadvertently make services visible to the public.
[ ] Create test and staging resources in a separate AWS account to that used by production resources.
[ ] Isolate logical services in separate VPCs and peer VPCs to provide inter-service communication.
[ ] Ensure all services only accept data from a minimal set of IP addresses.
[ ] Restrict outgoing IP and port traffic to minimize APTs and “botification”.
[ ] Always use AWS IAM roles and not root credentials.
[ ] Use minimal access privilege for all ops and developer staff.
[ ] Regularly rotate passwords and access keys according to a schedule.
Infrastructure
[ ] Ensure you can do upgrades without downtime. Ensure you can quickly update software in a fully automated manner.
[ ] Create all infrastructure using a tool such as Terraform, and not via the cloud console. Infrastructure should be defined as “code” and be able to be recreated at the push of a button. Have zero tolerance for any resource created in the cloud by hand — Terraform can then audit your configuration.
[ ] Don’t SSH into services except for one-off diagnosis. Using SSH regularly, typically means you have not automated an important task.
[ ] Don’t keep port 22 open on any AWS service groups on a permanent basis. If you must use SSH, only use public key authentication and not passwords.
[ ] Create immutable hosts instead of long-lived servers that you patch and upgrade. (See Immutable Infrastructure Can Be More Secure).
[ ] If not using Immutable Infrastructure (bad), ensure you have an automated system to patch and update all servers and regularly update your AMIs and rotate your servers to prevent long-lived APTs.
[ ] Power off unused services and servers. The most secure server is one that is powered down. Schedule dev servers to be powered down after hours when not required.
[ ] Use an Intrusion Detection System to minimize APTs.
Denial of Service Protection
[ ] Make sure that DOS attacks on your APIs won’t cripple your site. At a minimum, have rate limiters on your slower API paths and authentication related APIs like login and token generation routines. Consider CAPTCHA on front-end APIs to protect back-end services against DOS.
[ ] Enforce sanity limits on the size and structure of user submitted data and requests.
[ ] Perform Chaos testing to determine how your service behaves under stress.
[ ] Consider using Distributed Denial of Service (DDOS) mitigation via a global caching proxy service like CloudFlare. This can be turned on if you suffer a DDOS attack and otherwise function as your DNS lookup.
Hack Yourself
[ ] Audit your design and implementation.
[ ] Do penetration testing — hack yourself, but also have someone other than you do pen testing as well.
[ ] Proactively test your app beyond normal use. Consider the OWASP test checklist to guide your test hacking.
Incident Response
[ ] Train staff (especially senior staff) as to the dangers and techniques used in security social engineering.
[ ] Have a threat model that describes what you are defending against. It should list and prioritize the possible threats and actors.
[ ] Setup a standard email account and web page dedicated for users to report security issues (security@example.com and /security).
[ ] Have a practiced security incident plan. One day, you will need it.
Security is a Journey
Most of all, remember that security is a journey and cannot be "baked-in" to the product just before shipping. I hope this checklist will prompt you through your entire development lifecycle to improve the security of your services.
Version 1 of this checklist can be found at Web Developer Security Checklist V1
About SenseDeep
SenseDeep is an observability platform for AWS developers to accelerate the delivery and maintenance of serverless applications.
SenseDeep helps developers through the entire lifecycle to create observable, reliable and maintainable apps via an integrated serverless developer studio that includes design and debugging tools and deep insights into your serverless apps.
To try SenseDeep, navigate your browser to:
To learn more about SenseDeep please see:
Top comments (20)
Very good list, I would say that around half of them are not the Developer's responsibility (in a team with sys admins), never the less, the rules must be applied and the developers has to know them.
I'm reading the OWSAP and AWS guidelines, I know most of the items from this list but
As a suggestion, when you make starter lists like this try to keep them at minimum, as a newcomer to security this list scares me, I would rather say "I don't even know where to start, it will take me a long time so maybe I would do it later ..which means never".
You raise two interesting points. The first: non a devs responsibility ... as we move more toward a DevOps world, these roles are becoming combined and at the very least, devs need a strong appreciate and understand of all the issues if they are not directly responsible for them.
The second: a long list. I hear you. We've got lots of suggestions to add, but we have tried to only add the very important to the list. The idea of the list is not to be prescriptive of what you MUST do, but rather, for you to read the list at various points of your dev lifecycle to prompt your thinking to what items could be relevant at that point.
Thank you for reading and commenting.
You're actually missing quite a bit of the requirements by GDPR. Stuff like your optional encryption (at rest) are basically required if you process any kind of interesting personal data, there's data minimization which helps reduce risk of breaches as well, as well as breach notifications, and so on.
Additionally it's better for both your security and sanity NOT to e.g. log things that can directly identify a user but e.g. just their user ID, that way when you delete a user from your DB (e.g. as per "right to be forgotten"), you don't also have to scan through your logs to delete them. You sort of should delete the data from your backups though - but in practice if you secure them well (both encrypt, and limit access, as well as retention), and make sure that in case you restore something the data is deleted again, you're probably fine.
Annoyingly the GDPR regulation is super vague in some parts, and has really crazy requirements in other ways, but unfortunately it is now a reality and affects everyone.
Anyway, much of this should definitely be considered optional, and far from required to make your first MVP, so while the checklist is pretty good and has a lot of good points, it's definitely wrong to mention the MVP here. No sensible person goes through the effort and investment of setting up all these systems before launching their product.
Thanks for the prompt on GDPR. Security of data is important. I've got an item about encrypt at rest, but would be good to highly the GDPR mandate. Thanks too for the suggestion on log data lines. Any other GDPR high priority issues?
Thanks
GDPR is such an opaque beast it's hard to come up with clear and obvious answers to that, but there's a few things that pop into mind that are definitely helpful and good to keep in mind in general.
Setting up a list of 3rd parties you depend on for hosting and traffic (AWS/GCP/Azure, CloudFlare, etc.), or otherwise share personal data with (using their analytics systems, and other integrations) is going to help you realize just how many additional risks you have to worry about, and will make communicating this information easier to customers. E.g. something like: paypal.com/uk/webapps/mpp/ua/third...
Similarly keeping a list of all the systems you store personal data in, in any format: Google Drive, Sharepoint, Dropbox, your employees' personal laptops, your ZenDesk and Slack channel with instant notifications for new support requests, the "Top 10 support issues of 2018" document with copy & pasted ticket contents, etc.
All of these things, not just your database servers and application code, need to be secured. If you use Google G Suite or Office 365 or similar, make sure you require 2 Factor Authentication from everyone, including the CEO. Get e.g. Yubikeys.
Make sure everyone, ESPECIALLY the CEO has full disk encryption on their laptop, and that the machine requires a password on boot, on wakeup, and has a screensaver that locks it as well.
Ensure you get actual consent for pretty much everything, this means actual opt-in, not pre-checked checkboxes with intentionally bad UX (e.g. being the only checkbox label on your site that doesn't react to clicks) to subscribe to your news letter.
Have a plan for deleting stale personal data that you no longer need or have a legitimate use for, and no, the CEO saying "we might want to take a look at it in 20 years" is not a legitimate use - well anonymized data can still be used for analytics for a long time though.
You should generally speaking avoid collecting sensitive personal data, and what is considered "sensitive" might surprise you. If you have data on race, political preferences, religion, union status, health, sex life, or sexual orientation of a person that is considered sensitive, and many other seemingly innocuous things like "hobbies" could easily contain sensitive information. You should limit the amount of sensitive data you store, and how you store it must be particularly carefully done.
Have a process ready for what to do when people request a copy of their data, and what to do when people request their data to be deleted. Preferably an automated one. They can also request their data to be fixed if they detect a mistake. You also need to know the source of the data. Basically be ready to receive something like: linkedin.com/pulse/nightmare-lette...
One of the most obvious questions that comes to my mind, which really isn't obvious to most people, is do you really need that email address in plain text in your login information, or could that also be hashed? If they subscribe to your newsletter, maybe store their email only in that case. Reset password could require them to enter the same email as before. I wonder if there are email tokenization services similar to what Stripe does with credit cards, that'd be great for email notifications.
There's a few relevant things that I can also link to:
Wow, thank you so much for this detail. I love the nightmare letter! I'll mine your comments and try to distill into a few points that captures the important parts.
You should do a DevTo article about GDPR!
-- Added comments:
Here are three items I've distilled from your text:
Don't store sensitive data unless you truly need it. This means email addresses, personally identifying information and other personal information in general. Treat sensitive data like radioactive waste — i.e. there is an real, large and ongoing cost to securing it, and one day it can hurt you.
Keep a complete list of all the places you store sensitive information: databases, file systems, Dropbox, GitHub, Vault, Office docs and even the paper folder. This is useful to manage, required by GDPR and essential if hacked. You need to be able to locate all sensitive information.
If subject to GDPR, make sure you really understand the requirements and design it in from the start. For some, it will represent a major change in design and thinking. /Two links here/
Could add oauth token validation at the load balancer and a few items about firewalls (perimeter, microsegmentation, waf)
Great list btw.
Two minds suggesting the same thing -- must be good ;-)
Could you distill your suggestion about firewalls into a simple focussed point?
I wouldn't lump WAFs in with standard firewalls.
Perimeter firewalls are your first line of defense against intrusion, and segment your network based on need to access other networks. Microsegmentation firewalls ensure the only intra-segment network traffic that is going on is approved traffic. Devs need to supply source/destination IP addresses and ports to allow traffic.
Web Application Firewalls (WAFs) perform an inspection of HTTP requests to halt attacks on web servers.
I'm trying to craft a point to address this simply.
Looks good to me! I saw you mentioned CloudFlare as a DDoS mitigator, they also provide a WAF service, which would be good in the HTTP traffic section.
Got it, thank you!
I'm writing applications right now; saved!
Thank you! This is a really nice compilation.
Thank you. All suggestions gratefully received too.
This is a very nice list! It shows me that I have a lot to research too!
I will definitely print it and use it before I release my products!
Thanks for the list! I'll keep it for later use.
For the 2 first sections, I would suggest outsourcing this to a service such as Auth0. It removes a lot of the burden.
Easy add. Auth0 or Cognito come to mind.
Thank you.
This is a great list. Thanks!
Thanks. Painfully learned - some of those items!!