Security in web development
The essential guide to secure web development
Developing secure and reliable cloud-based web applications is very, very difficult. If you think otherwise, you are either not of this world, or your life has not yet taught you a lesson.
If you have already become infected with the idea of a “minimum viable product”. And consider that in a month you can create both a useful and safe product – think twice before releasing it. After reviewing the checklist, you will realize that you leave a lot of vulnerabilities.
The least that can be done in such a situation is to honestly warn users that the product is still at the working prototype stage and full security is not yet guaranteed.
We have been developing secure web applications for over 4 years and have included in the list the most important issues we have encountered during this time.
- Store user identification data and confidential data (tokens, email addresses, payment details) in encrypted form.
- If the database supports encryption of stored data (for example, AWS Aurora), connect it to protect the data on the disk. Make sure all backups are also stored in encrypted form.
- Use the lowest privilege level to access user accounts in the database. Do not use the database root account.
- Store and distribute sensitive data using a keystore designed for this purpose. Do not use hardcode in applications.
- Prevent SQL injections using only prepared SQL queries. For example: if you use NPM, do not use npm-mysql, use npm-mysql2, which supports prepared expressions.
- Ensure that all application components are checked for vulnerabilities for each version transferred to production. These include O/S, libraries and packages. Verification should be automated during the CI-CD process (CI – continuous integration, CD – continuous delivery).
- Be equally vigilant about both the security of the development environment and the security of the production server. Create software in a secure, isolated development environment.
- Ensure that all passwords are hashed using an appropriate cryptographic function, for example, bcrypt. Never write your own hash function and correctly initialize the used cryptographic library with random data.
- Implement simple but adequate password rules that encourage users to enter long unique passwords.
- In all services, use multi-factor authentication to login.
- Make sure that DDoS attacks on your API will not harm the site. At a minimum, protect API bottlenecks, such as login and token generation procedures.
- Provide reasonable limits on the size and structure of user provided data and queries.
- Reduce DDoS attacks with a global proxy caching service, for example, CloudFlare. It turns on when you are under a DDOS attack, and normally functions as a DNS lookup.
- Use TLS for the entire site, not just login and response forms. Never use TLS for a login form only.
- Cookies must be “secure” (secure) and httpOnly, and the scope must be determined by the attributes path and domain.
- Use Content Security Policy, avoiding unsafe backdoor. Flour with the settings are worth it.
- Use X-Frame-Option, X-XSS-Protection headers in client responses.
- Use the HSTS mechanism to force access via the TLS protocol. Redirect all HTTP requests to HTTPS on the server for backward compatibility.
- Use CSRF tokens in all forms and a new SameSite Cookie response header that captures CSRF one-time for all browsers.
- Ensure that there are no shared resources in the API.
- Make sure that when using your API, users are fully identified and authorized.
- Perform client side input verification for quick user feedback, but never trust it.
- Confirm every bit of user input using server whitelists. Never enter user content directly into the response. Never use user input in SQL queries.
- Make sure all services have the minimum number of open ports. While the principle of “security through obscurity” does not provide complete protection, the use of non-standard ports will make life a little harder for intruders.
- Place the backend base on private VPCs that are not visible on the public network. Be very careful when setting up AWS security groups and peer-to-peer VPCs – you can inadvertently make services public.
- Isolate logical services in separate VPCs and peer-to-peer VPCs for inter-service communication.
- Make sure that all services accept data only from the minimum set of IP addresses.
- Limit outgoing IP and port traffic to minimize APT and “bot”.
- Always use AWS IAM roles, not root credentials.
- Use minimum access rights for all employees and developers.
- Regularly change passwords and access keys in accordance with the schedule.
- Make sure that upgrades are done without downtime, and the software is updated automatically.
- Build your infrastructure with tools like Terraform, not through a cloud console. The infrastructure should be defined as a “code” and recreated at the touch of a button.
- Use centralized logging for all services. Do not use SSH to access or receive logs.
- Do not use SSH in services, except perhaps a one-time diagnostic. Regular use of SSH, as a rule, means that you have not automated everything as it should.
- Do not leave port 22 permanently open on any AWS service groups.
- Create immutable hosts instead of long-lived servers that you patch and update.
- Use an intrusion detection system to minimize APT.
- Shut down unused services and servers. The safest server is a shutdown server.
- Conduct an audit of both the project and the finished implementation.
- Perform a penetration test – hack yourself, and also ask someone else to hack you.
The main thing – plan
- Use threat modeling to see what you need to protect against. The model should list and prioritize potential threats and all possible actors.
- Create an incident plan. One day you will need it.