{"id":13843934,"url":"https://github.com/subhajit0x/Node-JS-Security-Tips","last_synced_at":"2025-07-11T20:30:55.479Z","repository":{"id":46142366,"uuid":"515124899","full_name":"subhajit0x/Node-JS-Security-Tips","owner":"subhajit0x","description":"All the resources for code review ;)","archived":false,"fork":false,"pushed_at":"2022-09-13T12:07:30.000Z","size":15,"stargazers_count":8,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-11-21T15:39:37.454Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/subhajit0x.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null}},"created_at":"2022-07-18T09:51:40.000Z","updated_at":"2024-07-23T06:32:26.000Z","dependencies_parsed_at":"2023-01-18T06:01:10.846Z","dependency_job_id":null,"html_url":"https://github.com/subhajit0x/Node-JS-Security-Tips","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/subhajit0x/Node-JS-Security-Tips","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/subhajit0x%2FNode-JS-Security-Tips","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/subhajit0x%2FNode-JS-Security-Tips/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/subhajit0x%2FNode-JS-Security-Tips/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/subhajit0x%2FNode-JS-Security-Tips/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/subhajit0x","download_url":"https://codeload.github.com/subhajit0x/Node-JS-Security-Tips/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/subhajit0x%2FNode-JS-Security-Tips/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264892036,"owners_count":23679208,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-04T17:02:30.922Z","updated_at":"2025-07-11T20:30:55.167Z","avatar_url":"https://github.com/subhajit0x.png","language":null,"funding_links":[],"categories":["Others"],"sub_categories":[],"readme":"# Node JS Security Tips\n\n\n# 1. Overview\n\nThese are generally applied to all the frameworks. Summarizing posts from different references.\n\nSecurity HTTP Headers -\n\n- **Strict-Transport-Security** enforces secure (HTTP over SSL/TLS) connections to the server.\n- **X-Frame-Options** provides clickjacking protection.\n- **X-XSS-Protection** enables the Cross-site scripting (XSS) filter built into most recent web browsers.\n- **X-Content-Type-Options** prevents browsers from MIME-sniffing a response away from the declared content type.\n- **Content-Security-Policy** prevents a wide range of attacks, including Cross-site scripting and other cross-site injections.\n\nIn NodeJS it is easy to set these with helmet modules.\n\n```jsx\nvar express = require('express');\nvar helmet = require('helmet');\nvar app = express();\napp.use(helmet());\n```\n\nThese can also be implement on Server level without touching the codebase -\n\n```jsx\n# nginx.conf\n\nadd_header X-Frame-Options SAMEORIGIN;\nadd_header X-Content-Type-Options nosniff;\nadd_header X-XSS-Protection \"1; mode=block\";\nadd_header Content-Security-Policy \"default-src 'self'\";\n```\n\n### Sensitive Data on the Client Side\n\nWhen deploying front-end applications make sure that you never expose API secrets and credentials in your source code, as it will be readable by anyone.\n\nThere is no good way to check this automatically, but you have a couple of options to mitigate the risk of accidentally exposing sensitive data on the client side:\n\n- use of pull requests\n- regular code reviews\n- Code obfuscation\n\n## Ratelimiting\n\nTo protect your applications from these kind of attacks you have to implement some kind of rate-limiting. In Node.js you can use the ratelimiter.\n package.\n\n```jsx\nvar email = req.body.email;\nvar limit = new Limiter({ id: email, db: db });\n\nlimit.get(function(err, limit) {\n\n});\n```\n\nIt’s not the only way , You can wrap into a middleware and just drop it into any application.Both Express and Koa has great middlewares.\n\n```jsx\nvar ratelimit = require('koa-ratelimit');\nvar redis = require('redis');\nvar koa = require('koa');\nvar app = koa();\n\nvar emailBasedRatelimit = ratelimit({\n  db: redis.createClient(),\n  duration: 60000,\n  max: 10,\n  id: function (context) {\n    return context.body.email;\n  }\n});\n\nvar ipBasedRatelimit = ratelimit({\n  db: redis.createClient(),\n  duration: 60000,\n  max: 10,\n  id: function (context) {\n    return context.ip;\n  }\n});\n\napp.post('/login', ipBasedRatelimit, emailBasedRatelimit, handleLogin);\n```\n\nTry with hydra which is a bydefault Kali Linux tool.\n\n## **Cookie Flags**\n\n- **secure** – this attribute tells the browser to only send the cookie if the request is being sent over HTTPS.\n- **HttpOnly** – this attribute is used to help prevent attacks such as cross-site scripting, since it does not allow the cookie to be accessed via JavaScript.\n\n### Cookie Scope\n\n- **domain** – this attribute is used to compare against the domain of the server in which the URL is being requested. If the domain matches or if it is a sub-domain, then the path attribute will be checked next.\n- **path** – in addition to the domain, the URL path that the cookie is valid for can be specified. If the domain and path match, then the cookie will be sent in the request.\n- **expires** – this attribute is used to set persistent cookies, since the cookie does not expire until the set date is exceeded\n\nUsing a wrapper for the cookie session - \n\n```jsx\nvar cookieSession = require('cookie-session');\nvar express = require('express');\n\nvar app = express();\n\napp.use(cookieSession({\nname: 'session',\nkeys: [\nprocess.env.COOKIE_KEY1,\nprocess.env.COOKIE_KEY2\n]\n}));\n\napp.use(function (req, res, next) {\nvar n = req.session.views || 0;\nreq.session.views = n++;\nres.end(n + ' views');\n});\n\napp.listen(3000);\n```\n\n## CSRF\n\nIn Node.js to mitigate this kind of attacks you can use the csrf module. As it is quite low-level, there are wrappers for different frameworks as well. \n\nIt can happen because cookies are sent with every request to a website – even when those requests come from a different site.\n\n### Example\n\n```\n\u003cbody onload=\"document.forms[0].submit()\"\u003e\n  \u003cform method=\"POST\" action=\"http://yoursite.com/user/delete\"\u003e\n    \u003cinput type=\"hidden\" name=\"id\" value=\"123555.\"\u003e\n  \u003c/form\u003e\n\u003c/body\u003e\n\n```\n\nThe result of the above snippet can easily result in deleting your user profile.\n\n### How to prevent it?\n\nTo prevent CSRF, you should implement the synchronizer token pattern – luckily the Node community has already done it for you. In short, this is how it works:\n\n1. When a `GET` request is being served check for the CSRF token – if it does not exists, create one\n2. When a user input is showed, make sure to add a hidden input with the CSRF token’s value\n3. When the form is sent, make sure that the value coming from the form and from the session are a match.\n\nOne example for this is the csurf module: an express middleware for CSRF protection.\n\nOn the route handler level you have to do something like this:\n\n```jsx\nvar cookieParser = require('cookie-parser');\nvar csrf = require('csurf');\nvar bodyParser = require('body-parser');\nvar express = require('express');\n \n// setup route middlewares \nvar csrfProtection = csrf({ cookie: true });\nvar parseForm = bodyParser.urlencoded({ extended: false });\n \n// create express app \nvar app = express();\n \n// we need this because \"cookie\" is true in csrfProtection \napp.use(cookieParser());\n \napp.get('/form', csrfProtection, function(req, res) {\n  // pass the csrfToken to the view \n  res.render('send', { csrfToken: req.csrfToken() });\n});\n \napp.post('/process', parseForm, csrfProtection, function(req, res) {\n  res.send('data is being processed');\n});\n```\n\n**Frontend :-** \n\n```jsx\n\u003cform action=\"/process\" method=\"POST\"\u003e\n  \u003cinput type=\"hidden\" name=\"_csrf\" value=\"{{csrfToken}}\"\u003e\n  \n  Favorite color: \u003cinput type=\"text\" name=\"favoriteColor\"\u003e\n  \u003cbutton type=\"submit\"\u003eSubmit\u003c/button\u003e\n\u003c/form\u003e\n```\n\n \n\n## Data Validation -\n\n### OS injection  -\n\nIn practice, if you have a URL like:\n\n```\nhttps://example.com/downloads?file=user1.txt\n\n```\n\nit could be turn into:\n\n```\nhttps://example.com/downloads?file=%3Bcat%20/etc/passwd\n\n```\n\nIn this example `%3B` becomes the semicolon, so multiple OS commands can be run.\n\n**To defend against these kind of attacks make sure that you always filter/sanitize user input.**\n\n## **SSL Version, Algorithms, Key length**\n\n**Checking for Certificate information**\n\n```\nnmap --script ssl-cert,ssl-enum-ciphers -p 443,465,993,995 www.example.com\n\n```\n\n**Testing SSL/TLS vulnerabilities with sslyze**\n\n```\n./sslyze.py --regular example.com:443\n```\n\nChecking **Strict-Policy** \n\n```jsx\ncurl -s -D- [https://twitter.com/](https://twitter.com/) | grep -i Strict\n```\n\n*Great tool to check headers* - [https://securityheaders.com/](https://securityheaders.com/)\n\n## DDOS  -\n\nThis kind of attack exploits the fact that most Regular Expression implementations may reach extreme situations that cause them to work very slowly. These Regexes are called Evil Regexes:\n\nTo check your Regexes against these, you can use a Node.js tool called [safe-regex](https://www.npmjs.com/package/safe-regex). *It may give false-positives, so use it with caution.*\n\n```\n$ node safe.js '(beep|boop)*'\ntrue\n$ node safe.js '(a+){10}'\nfalse\n```\n\n# Error Handling\n\n### Error Codes, Stack Traces\n\nDuring different error scenarios the application may leak sensitive details about the underlying infrastructure, like: `X-Powered-By:Express`.\n\nStack traces are not treated as vulnerabilities by themselves, but they often reveal information that can be interesting to an attacker. Providing debugging information as a result of operations that generate errors is considered a bad practice. You should always log them, but do not show them to the users.\n\n# NPM\n\nWith great power comes great responsibility – **[NPM](https://blog.risingstack.com/glossary/npm/)**npm is a software registry that serves over 1.3 million packages. npm is used by open source developers from all around the world to share and borrow code, as well as many businesses. There are three components to npm: the website the Command Line Interface (CLI) the registry Use the website to discover and download packages, create user profiles, and... has lots of packages what you can use instantly, but that comes with a cost: you should check what you are requiring to your applications. They may contain security issues that are critical.\n\n### The Node Security Project\n\nLuckily the Node Security project has a great tool that can check your used modules for known vulnerabilities.\n\n```\nnpm i nsp -g\n# either audit the shrinkwrap\nnsp audit-shrinkwrap\n# or the package.json\nnsp audit-package\n```\n\n## Eval()\n\nEval is not the only one you should avoid – in the background each one of the following expressions use `eval`:\n\n- `setInterval(String, 2)`\n- `setTimeout(String, 2)`\n- `new Function(String)`\n\nBut why should you avoid `eval`?\n\nIt can open up your code for injections attacks.\n\n# Say no to `sudo node app.js`\n\nI see this a lot: people are running their Node app with superuser rights. Why? Because they want the application to listen on port 80 or 443.\n\nThis is just wrong. In case of an error/bug your process can bring down the entire system, as it will have credentials to do anything.\n\n# Content Security Policy\n\n\u003e Content Security Policy (CSP) is an added layer of security that helps to detect and mitigate certain types of attacks, including Cross Site Scripting (XSS) and data injection attacks.\n\u003e \n\nCSP can be enabled by the `Content-Security-Policy` HTTP header.\n\n### Example\n\n`Content-Security-Policy: default-src 'self' *.mydomain.com`\n\nThis will allow content from a trusted domain and its subdomains.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsubhajit0x%2FNode-JS-Security-Tips","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsubhajit0x%2FNode-JS-Security-Tips","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsubhajit0x%2FNode-JS-Security-Tips/lists"}