“So Long And Thanks For All The Phishing” by Abraham Joel Pena Puelo / CC BY 4.0
Is your code secure?
Encryption, hashing, API security, SQL injections, CSRF, XSS, DoS, HSTS, RBAC, .... Oh, my.
When I started my programming journey, I didn't even know that I should care about software security. Then I got in contact with this entire area. And all those things blew my mind.
But with time, I learned what to look for when creating software.
This article targets software engineers in web, api, and app development, but most security measures apply to other application types, too!
I structured the security measures in three sections:
This article only gives you an overview of what is important. Take this as a starting point. Deep dive into each security measure and learn how to apply it in your code base.
This includes build and runtime dependencies, runtime engines (like Node.js), and OS versions. When you use Docker, also update that base image regularly.
APIs and websites should only be accessible via HTTPS. This secures your traffic from eavesdropping and certifies to your user they are talking to you.
Only offer recent versions of TLS (1.2 & 1.3). And don't offer TLS 1.1 or lower, or any version of SSL (those versions are insecure and end of life).
Expose web sockets only via “web socket secure” (wss
).
This is the TLS-secured version of web sockets.
On plain HTTP requests only allow redirect to HTTPS.
You should sanitize user inputs (or not, depending on who you ask 😄).
Start with validating user input, both in the form fields and at the api endpoint. Be strict about the input you receive. Enforce the correct type (number, string, ...). Use input whitelist where possible (e.g. enums). Use variable binding when storing data in a database, to prevent SQL injection (more on that below).
An interesting rule is to "Filter Input" and "Escape Output".
Don't use dynamic user input in your regex. Learn how to avoid Regular Expression Denial of Service (ReDoS)
This one is simple.
Never use dangerous functions like JS eval
, unless you know what you're doing.
Make sure files have the correct content type (use a whitelist).
Also, validate the content type, don't trust the content-type
header.
Set file size limits.
Set the filename to something your application generates.
Only allow authorized users to upload files.
Learn more about file upload verification in the OWASP cheat sheet for file upload security.
Use bcrypt unless you have a reason not to (see the OWASP password security cheat sheet). Or use an Auth Provider like auth0.com or Azure ADB2C (or whatever is available for you).
Or at least use variable substitution. This prevents SQL injections.
Offer concrete actions on defined resources. Only allow certain data manipulation, don't give users direct access to your database. Creat your API based on REST or GraphQL principles.
👉 This point is so important that I wanted to list it separately.
This is data like database secrets or access keys for external APIs.
Use environment variables. Don't check these env variables into version control (no default or hard-coded credentials).
Locally, you can use something like .env
files.
Your app either reads these files, or they set your env when executed.
CI/CD always provide a way to set env securely.
In production, the setup of secure environment variables changes depending on your hosting environment.
You could be able to set env directly in your hosting environment (like Heroku). Hosting platforms often call these settings "secure environment variables". Kubernetes is somewhat more complicated. Check out Hashicorp Vault, Helm Secrets, and Sealed Secrets to find out what works for you.
When you manage your own server, research best practices for the OS + Language combination you use. Make sure that credentials:
This helps to prevent Denial of Service (DoS) attacks.
This also helps to prevent DoS attacks.
Receive notifications on events that should not happen.
Identify security incidents, like configuration changes.
Monitor policy violations, like unauthorized
errors.
Log internal server errors (which should not happen).
Discuss what makes sense for your team and regularly improve your logging approach.
Don't keep unused software on your production machines and Docker images. Use the smallest possible version of your operating system, disable what you don't need and only install what you need.
Offer only the necessary API resources, not more. Disable debugging endpoints by default, only enable them when needed.
There are two parts to session management: authentication and authorization.
When a user first uses your application, you don't know who they are. They must authenticate to answer the question "who are you?" This usually happens via your login form or a third party login provider.
You then give them a safe session identifier or a Json Web Token (JWT). Your backend service either stores a list of all currently valid session identifiers. With JWTs, it knows how to verify the JWT a user provides. For session management, it is crucial that you provide a way to invalidate or blacklist sessions, to handle, e.g., log outs or user permission changes.
On each subsequent request, your users provide their session identifier. Authorization then answers the question: "is this user allowed to do that?" General rules for authorization are: Authorize on the server, not the client. Deny by default. Authorize actions on resources. Use a concept like role-based access control (RBAC) or attribute-based access control (ABAC). Find out more about RBAC vs ABAC.
rel="noopener noreferrer"
to prevent tabnabbingSecurity errors can be very costly. Either for your company or for your client. Make sure you follow the basic best practices, to prevent the worst.
Software security is, like all security, the effort to make the cost-benefit analysis of the attacker negative.
For your run-off-the-mill web app, following the basics is more than most of the others do. The more valuable your application and its data are, the higher your efforts on security should be.
There are many more security best practices than I described here. This list serves as a starting point about what to look for when developing software. Go check out the OWASP Cheat Sheet Series. They provide a great "collection of high value information on specific security topics".
Deep dive into the measures you know less about. Pick one or two and see if you already use them in your application. If not, plan how to do it. Then implement it. Repeat for other measures you're not familiar with.
Disclaimer: I am not a security specialist. Just a developer concerned with application and api security trying to teach some best practices. This list is not exhaustive. Always do your own research.