Security Checklists
node.js server security
Use strong secrets and store them safely
- use strong secrets: long and complex
- use individual secrets and do not share them
- store secrets encrypted and privately
- remove dated, default and unnecessary accesses, especially from common applications like DBs
- provide secrets to the application in env vars at runtime
- do not commit files that contain secrets: securing your repository
Use the latest version of the frameworks/libraries
Using the latest version of the software does not mean that it's more secure than the older one, but at least vulnerabilities are not yet discovered and old vulnerabilities should be resolved.
npm i -g npm-check-udpates
ncu
Check for known vulnerabilities
npm registry contains known vulnerabilities of their packages, that can be checked by
npm audit
Remove information that identify the tech
For example: X-Powered-By
header and cookie sessionid
name may reveal the technologies running on the server and that can address attacks for know vulnerabilities, especially if they are dated.
- HTTPS
Use https over http to encrypt communication and avoid intermediate network points to sniff transferring data.
See MITM attack
Secure cookies
- do not store sensitive data in cookies
- use
session
cookies - use
HttpOnly
,SameSite
andSecure
flags - restrict access to a single domain, without subdomains
Use an helmet
Use an "helmet" middleware to harden the web framework. It removes headers that identify the framework and add secure headers.
Follow headers should be set as base
Strict-Transport-Security: max-age=31536000; includeSubDomains
prevent any communications from being sent over HTTP to the specified domain and will instead send all communications over HTTPS, formax-age
(one year in the example)X-Frame-Options: SAMEORIGIN
prevent that the current page can be shown in an iframe from another domainX-DNS-Prefetch-Control: off
prevent links prefetching, so the browser will not load unintended urls by its ownX-Content-Type-Options: nosniff
prevent the browser from interpreting different content from the one declared inContent-Type
Content-Security-Policy: script-src 'self'
define content sources that are approved and thus allowing the browser to load them. It requires fine-tuning for web apps, see full document.X-XSS-Protection: 1; mode=block
enable XSS filter in modern browsers
Useful lib:
Prevent application crash
Manage different form of input from the expected ones; use try-catch
blocks for faultable operations - most for the frameworks do that in route handlers
Control inputs
-
Input from "the outside" can be malicious, be always diffident with what the server could receive.
-
Always validate inputs coming from request:
query
,body
, url path (often inparams
using a framework). -
Do not forward straight input to other applications that the web server communicates, for example composing SQL statement and pass to DB cause sql injections.
Use a validation library for inputs, like ajv, joi, superstruct or even better apply a validation schema.
See fastify validation.
Control outputs
Encode output properly, escaping content that can inject malicious code.
While modern frontend frameworks usually prevent unintentional code injection (see React dangerouslySetInnerHTML), the server is still the source of content.
On SSR, content responsibility is a server duty.
Useful libraries:
See Improper Output Handling, XSS attack.
Control source
- setup CORS policy properly - most frameworks have a plugin
- use a synchronizer token to checksum the request
- implement a "blacklist"/"whitelist" to prevent known malicious requests, usually filtering by ip, that can be updated at runtime
- use multi-factor authentication for sensible operations (always when involving money)
See CSRF attack.
Control request rate
Limit the amount of requests to a sustainable rate and slow down repetitive failing operations (for example login) to preserve resources for the designed purpose.
Useful libraries:
See
Control resources
Avoid the server crash because is out of resources (like disk space and memory) and also tracking regular activities. Monitoring is very different because of the environment (cloud, container, vps, and so on) and method (trace collector, polling queries) but always be sure to take under control resources usage and availability. Abnormal traffic is evidence of an attack.
Test
A +95% coverage is a good index of server reliability: while even full covered code can have bugs, tested code should avoid the most evident ones.
References
- "Node Cookbook", chap. 8 "Dealing with security"
- http://projects.webappsec.org/f/WASC-TC-v2_0.pdf
- https://owasp.org/www-project-secure-headers/#div-headers
- https://cheatsheetseries.owasp.org/index.html
Database
Connecting to the Database
The backend database used by the application should be isolated as much as possible, in order to prevent malicious or undesirable users from being able to connect to it. Exactly how this is achieved will depend on the system and network architecture. The following options could be used to protect it:
Networking
- Disabling network (TCP) access and requiring all access is over a local socket file or named pipe.
- Configuring the database to only bind on localhost.
- Restricting access to the network port to specific hosts with firewall rules.
- Placing the database server in a separate DMZ isolated from the application server.
Similar protection should be implemented to protect any web-based management tools used with the database, such as phpMyAdmin.
When an application is running on an untrusted system (such as a thick-client), it should always connect to the backend through an API that can enforce appropriate access control and restrictions. Direct connections should never be made from a thick client to the backend database.
Transport Layer Protection
Most databases will allow unencrypted network connections in their default configurations. Although some will encrypt the initial authentication (such as Microsoft SQL Server), the rest of the traffic will be unencrypted, meaning that all kinds of sensitive information will be sent across the network in clear text. The following steps should be taken to prevent unencrypted traffic:
- Configure the database to only allow encrypted connections.
- Install a trusted digital certificate on the server.
- Configure the client application to connect using TLSv1.2+ with modern ciphers (e.g, AES-GCM or ChaCha20).
- [ ]Configure the client application to verify that the digital certificate is correct.
Authentication
The database should be configured to always require authentication, including connections from the local server. Database accounts should be:
- Protected with strong and unique passwords.
- Used by a single application or service.
- Configured with the minimum permissions required as discussed in the permissions section below.
As with any system that has its own user accounts, the usual account management processes should be followed, including:
- Regular reviews of the accounts to ensure that they are still required.
- Regular reviews of permissions.
- Removing user accounts when an application is decommissioned.
- Changing the passwords when staff leave, or there is reason to believe that they may have been compromised. For Microsoft SQL Server, consider the use of Windows or Integrated-Authentication, which uses existing Windows accounts rather than SQL Server accounts. This also removes the requirement to store credentials in the application, as it will connect using the credentials of the Windows user it is running under. The Windows Native Authentication Plugins provides similar functionality for MySQL.
Storing Database Credentials
Database credentials should never be stored in the application source code, especially if they are unencrypted. Instead, they should be stored in a configuration file that:
- Is outside of the webroot.
- Has appropriate permissions so that it can only be read by the required user(s).
- Is not checked into source code repositories.
- Where possible, these credentials should also be encrypted or otherwise protected using built-in functionality, such as the web.config encryption available in ASP.NET.
Permissions
The permissions assigned to database user accounts should be based on the principle of least privilege (i.e, the accounts should only have the minimal permissions required for the application to function). This can be applied at a number of increasingly granular levels levels depending on the functionality available in the database. The following steps should be applicable to all environments:
- Do not use the built-in root, sa or SYS accounts.
- Do not grant the account administrative rights over the database instance.
- Only allow the account to connect from allowed hosts.
- This would often be localhost or the address of the application server.
- Only grant the account access to the specific databases it needs.
- Development, UAT and Production environments should all use separate databases and accounts.
- Only grant the required permissions on the databases.
- Most applications would only need SELECT, UPDATE and DELETE permissions.
- The account should not be the owner of the database as this can lead to privilege escalation vulnerabilities.
- Avoid using database links or linked servers.
- Where they are required, use an account that has been granted access to only the minimum databases, tables, and system privileges required.
For more security-critical applications, it is possible to apply permissions at more granular levels, including:
- Table-level permissions.
- Column-level permissions.
- Row-level permissions
- Blocking access to the underlying tables, and requiring all access through restricted views.
Database Configuration and Hardening
The underlying operating system for the database server should be hardened in the same way as any other server, based on a secure baseline such as the CIS Benchmarks or the Microsoft Security Baselines.
The database application should also be properly configured and hardened. The following principles should apply to any database application and platform:
- Install any required security updates and patches.
- Configure the database services to run under a low privileged user account.
- Remove any default accounts and databases.
- Store transaction logs on a separate disk to the main database files.
- Configure a regular backup of the database.
- Ensure that the backups are protected with appropriate permissions, and ideally encrypted.
Smart Contract Security Check list
- Unit Test Coverage
- Re-entry
- Review or question invocation of other contracts (dep)
Beware static analysis would not catch:
- Lack of privacy: everyone else can see transactions while they're queued in the pool
- Front running transactions
- Cryptographic operations
- Risky interactions with external DeFi components
Solidity specific
- Earth (Orbit/Moon)
- Mars
- Jupiter
- Saturn
- Uranus
- Neptune
- Comet Haley
Regulation
- is this thing advertised as security or asset? If this thing has current value and not or not only expectation to raise in value, then it gets away with not being a security. (e.g condo share to live in)