From 43c064aeb209b5fc089831a16526f9a9e9a79f16 Mon Sep 17 00:00:00 2001 From: Yoni Goldberg Date: Wed, 25 Jul 2018 11:28:09 +0300 Subject: [PATCH] Merged the security section --- README.md | 292 +++++++++++++++++- sections/security/avoideval.md | 19 ++ sections/security/bcryptpasswords.md | 28 ++ sections/security/childprocesses.md | 31 ++ .../security/commonsecuritybestpractices.md | 96 ++++++ sections/security/dependencysecurity.md | 62 ++++ sections/security/escape-output.md | 55 ++++ sections/security/expirejwt.md | 27 ++ sections/security/hideerrors.md | 22 ++ sections/security/limitrequests.md | 25 ++ sections/security/lintrules.md | 39 +++ sections/security/login-rate-limit.md | 51 +++ sections/security/non-root-user.md | 30 ++ sections/security/ormodmusage.md | 51 +++ sections/security/regex.md | 32 ++ sections/security/requestpayloadsizelimit.md | 60 ++++ sections/security/safemoduleloading.md | 13 + sections/security/sandbox.md | 27 ++ sections/security/secretmanagement.md | 31 ++ sections/security/secureheaders.md | 172 +++++++++++ sections/security/secureserver.md | 28 ++ sections/security/sessions.md | 39 +++ sections/security/validation.md | 64 ++++ 23 files changed, 1290 insertions(+), 4 deletions(-) create mode 100644 sections/security/avoideval.md create mode 100644 sections/security/bcryptpasswords.md create mode 100644 sections/security/childprocesses.md create mode 100644 sections/security/commonsecuritybestpractices.md create mode 100644 sections/security/dependencysecurity.md create mode 100644 sections/security/escape-output.md create mode 100644 sections/security/expirejwt.md create mode 100644 sections/security/hideerrors.md create mode 100644 sections/security/limitrequests.md create mode 100644 sections/security/lintrules.md create mode 100644 sections/security/login-rate-limit.md create mode 100644 sections/security/non-root-user.md create mode 100644 sections/security/ormodmusage.md create mode 100644 sections/security/regex.md create mode 100644 sections/security/requestpayloadsizelimit.md create mode 100644 sections/security/safemoduleloading.md create mode 100644 sections/security/sandbox.md create mode 100644 sections/security/secretmanagement.md create mode 100644 sections/security/secureheaders.md create mode 100644 sections/security/secureserver.md create mode 100644 sections/security/sessions.md create mode 100644 sections/security/validation.md diff --git a/README.md b/README.md index 4be70719..6481cace 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@
- 54 items Last update: July 15th, 2018 Updated for Node 8.11.3 LTS + 73 items Last update: July 25th, 2018 Updated for Node 8.11.3 LTS

@@ -39,7 +39,7 @@ Read in a different language: [![CN](/assets/flags/CN.png)**CN**](/README.chines 3. [Code Style Practices (12) ](#3-code-style-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) -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))


@@ -638,11 +638,295 @@ All statements above will return false if used with `===`

⬆ Return to top

-# `Security Practices` +# `6. Security Practices` +
+53 items +
+ +## ![βœ”] 6.1. Embrace linter security rules + + +**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) + +

+ +## ![βœ”] 6.2. Limit concurrent requests using a balancer or a middleware + + +**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) + +

+ +## ![βœ”] 6.3 Extract secrets from config files or use NPM package that encrypts them + + + +**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) + +

+ + +## ![βœ”] 6.4. Prevent query injection vulnerabilities with ORM/ODM libraries + + +**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) + +

+ + +## ![βœ”] 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) + +

+ +## ![βœ”] 6.6. Adjust the response HTTP headers for enhanced security + + +**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) + +

+ +## ![βœ”] 6.7. Constantly and automatically inspect for vulnerable dependencies + + +**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) + +

+ + +## ![βœ”] 6.8. Avoid using the Node.js Crypto library for passwords, use Bcrypt + + + +**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) + +

+ +## ![βœ”] 6.9. Escape HTML, JS and CSS output + + +**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) + +

+ +## ![βœ”] 6.10. Validate the incoming JSON schemas + + +**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) + +

+ + +## ![βœ”] 6.11. Support blacklisting JWT tokens + + +**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) + +

+ + +## ![βœ”] 6.12. Limit the allowed login requests of each user + + +**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) + +

+ + +## ![βœ”] 6.13. Run Node.js as non-root user + + +**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) + +

+ + +## ![βœ”] 6.14. Limit payload size using a reverse-proxy or a middleware + + +**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) + +

+ + +## ![βœ”] 6.15. Avoid JavaScript eval statements + + + +**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) + +

+ + +## ![βœ”] 6.16. Prevent evil regex from overloading your single thread execution + + +**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) + +

+ +## ![βœ”] 6.17. Avoid module loading require(someVariable) using a variable + + + +**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) + +

+ +## ![βœ”] 6.18. Run unsafe code in a sandbox + + +**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) + +

+ + +## ![βœ”] 6.19. Take extra care when working with child processes + + + +**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) + +

+ + +## ![βœ”] 6.20. Hide error details from the client + + +**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) + +

+ +## ![βœ”] 6.21. Configure 2FA for NPM or Yarn + + + +**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) + + +

+ +## ![βœ”] 6.22. Modify session middleware settings + + + +**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) + +

+ +## ![βœ”] 6.23. Avoid DOS attacks by explicitly setting when a process should crash + + +**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 + +


+ + +

⬆ Return to top

+ +# `API Practices` ## Our contributors are working on this section. Would you like to join? -


# `Performance Practices` diff --git a/sections/security/avoideval.md b/sections/security/avoideval.md new file mode 100644 index 00000000..8570e329 --- /dev/null +++ b/sections/security/avoideval.md @@ -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. \ No newline at end of file diff --git a/sections/security/bcryptpasswords.md b/sections/security/bcryptpasswords.md new file mode 100644 index 00000000..721b654b --- /dev/null +++ b/sections/security/bcryptpasswords.md @@ -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. diff --git a/sections/security/childprocesses.md b/sections/security/childprocesses.md new file mode 100644 index 00000000..16fddc7d --- /dev/null +++ b/sections/security/childprocesses.md @@ -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. diff --git a/sections/security/commonsecuritybestpractices.md b/sections/security/commonsecuritybestpractices.md new file mode 100644 index 00000000..fb9f6a27 --- /dev/null +++ b/sections/security/commonsecuritybestpractices.md @@ -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) + +

+ +## ![βœ”] 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 + +

+ +## ![βœ”] 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 + +

+ +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 + +


diff --git a/sections/security/dependencysecurity.md b/sections/security/dependencysecurity.md new file mode 100644 index 00000000..13f8f5b5 --- /dev/null +++ b/sections/security/dependencysecurity.md @@ -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`: + +![nsp check example](/assets/images/nsp.png) + +πŸ”— [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: +![synk GitHub example](/assets/images/snyk.png) + +πŸ”— [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: + +![synk github example](/assets/images/greenkeeper.png) +πŸ”— [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) diff --git a/sections/security/escape-output.md b/sections/security/escape-output.md new file mode 100644 index 00000000..b3ede563 --- /dev/null +++ b/sections/security/escape-output.md @@ -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 `
`. 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 + directly in a script + + inside an HTML comment + +
in an attribute name + + in a tag name + + directly in CSS + +``` + +### Code example - Un-innocent content that might be injected into a DB +```javascript +
+ A pseudo comment to the a post + +
+ +``` + +

+### 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 tags have special meaning: +This is bold text. +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> + + +

+### 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**." + + +

+### 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