Blockade

version types license style

Blockade ⚓️ is a lightweight package that adds optional security headers and cookie attributes for Node.js web frameworks.

Security HTTP headers and cookie attributes help enhance the security of your web application by enabling built-in browser security mechanisms.

Supported Node.js web frameworks:

AdonisJs, Express, Fastify, hapi, Koa, Meteor, Nest, Polka, restify, Sails, Total.js

Install

$ npm i blockade

After installing Blockade:

const blockade = require("blockade");

const secureHeaders = new blockade.SecureHeaders();
const secureCookie = new blockade.SecureCookie();

Documentation

Secure Headers

Security Headers are HTTP response headers that, when set, can enhance the security of your web application by enabling browser security policies.

You can assess the security of your HTTP response headers at securityheaders.com

Recommendations used by secure,py and more information regarding security headers can be found at the OWASP Secure Headers Project .

Server

Contain information about server software
Default Value: NULL (obfuscate server information, not included by default)

Strict-Transport-Security (HSTS)

Ensure application communication is sent over HTTPS
Default Value: max-age=63072000; includeSubdomains

X-Frame-Options (XFO)

Disable framing from different origins (clickjacking defense)
Default Value: SAMEORIGIN

X-XSS-Protection

Enable browser cross-site scripting filters
Default Value: 1; mode=block

X-Content-Type-Options

Prevent MIME-sniffing
Default Value: nosniff

Content-Security-Policy (CSP)

Prevent cross-site injections
Default Value: script-src 'self'; object-src 'self' (not included by default)*

Referrer-Policy

Enable full referrer if same origin, remove path for cross origin and disable referrer in unsupported browsers
Default Value: no-referrer, strict-origin-when-cross-origin

Cache-control / Pragma / Expires

Prevent cacheable HTTPS response
Default Value: no-cache, no-store, must-revalidate, max-age=0 / no-cache / 0

Feature-Policy

Disable browser features and APIs
Default Value: accelerometer 'none'; ambient-light-sensor 'none'; autoplay 'none'; camera 'none'; encrypted-media 'none'; fullscreen 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; midi 'none'; payment 'none'; picture-in-picture 'none'; speaker 'none'; sync-xhr 'none'; usb 'none'; vr 'none'; (not included by default)

Additional information

  • The Strict-Transport-Security (HSTS) header will tell the browser to only utilize secure HTTPS connections for the domain, and in the default configuration, including all subdomains. The HSTS header requires trusted certificates and users will unable to connect to the site if using self-signed or expired certificates. The browser will honor the HSTS header for the time directed in the max-age attribute (default = 2 years), and setting the max-age to 0 will disable an already set HSTS header. Use the { hsts: false } option to not include the HSTS header in Secure Headers.
  • The Content-Security-Policy (CSP) header can break functionality and can (and should) be carefully constructed, use the { csp : true } option to enable default values.

Usage

const secureHeaders = new blockade.SecureHeaders();
secureHeaders.framework(response);

Default HTTP response headers:

Strict-Transport-Security: max-age=63072000; includeSubdomains
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Referrer-Policy: no-referrer, strict-origin-when-cross-origin
Cache-control: no-cache, no-store, must-revalidate, max-age=0
Pragma: no-cache
Expires: 0

Options

You can toggle the setting of headers with default values by passing an object with new blockade.Header().default() or new blockade.Header().notSet() and override default values by passing new blockade.Header().set("custom") or policy to the following options:

  • server - set the Server header, e.g. new blockade.Server().set("Blockade") - (default= default=Server().notSet() )
  • hsts - set the Strict-Transport-Security header - (default= HSTS().default() )
  • xfo - set the X-Frame-Options header - (default= XFO().default() )
  • xxp - set the X-XSS-Protection header - (default= XXP().default() )
  • content - set the X-Content-Type-Options header - (default= Content().default() )
  • csp - set the Content-Security-Policy - (default= CSP().notSet() )
  • referrer - set the Referrer-Policy header - (default= Referrer().default() )
  • cache - set the Cache-control and Pragma headers - (default= Cache().default() )
  • feature - set the Feature-Policy header - (default= Feature().notSet() )

Example:

const blockade = require("blockade");

const secureHeaders = new blockade.SecureHeaders({
  server: "Blockade",
  csp: true,
  hsts: false
});

. . .

secureHeaders.framework(response)

  . . .

Secure Cookies

Path

The Path directive instructs the browser to only send the cookie if provided path exists in the URL.

Secure

The Secure flag instructs the browser to only send the cookie via HTTPS.

HttpOnly

The HttpOnly flag instructs the browser to not allow any client side code to access the cookie’s contents.

SameSite

The SameSite flag directs the browser not to include cookies on certain cross-site requests. There are two values that can be set for the same-site attribute, lax or strict. The lax value allows the cookie to be sent via certain cross-site GET requests, but disallows the cookie on all POST requests. For example cookies are still sent on links <a href=“x”>, prerendering <link rel=“prerender” href=“x” and forms sent by GET requests <form-method=“get”..., but cookies will not be sent via POST requests <form-method=“post”..., images <img src=“x”> or iframes <iframe src=“x”>. The strict value prevents the cookie from being sent cross-site in any context. Strict offers greater security but may impede functionality. This approach makes authenticated CSRF attacks impossible with the strict flag and only possible via state changing GET requests with the lax flag.

Expires

The Expires attribute sets an expiration date for persistent cookies.

Usage

const secureCookie = new blockade.SecureCookie();
secureCookie.framework(response, "foo", "bar");

Default Set-Cookie HTTP response header:

Set-Cookie: foo=bar; Path=/; secure; HttpOnly; SameSite=lax

Options

You can modify default cookie attribute values by passing the following options:

  • name - set the cookie name (string, No default value)
  • value - set the cookie value (string, No default value)
  • path - set the Path attribute, e.g. path=“/blockade” (string, default=“/”)
  • secure - set the Secure flag (bool, default=True)
  • httpOnly - set the HttpOnly flag (bool, default=True)
  • sameSite - set the SameSite attribute, e.g. {value: "Strict" }, {value: "Lax" } or False default={value: “Lax” }
  • expires - set the Expires attribute with the cookie expiration in hours, e.g. expires=1 (number / bool, default=False)

Example:

const blockade = require("blockade");

const secureCookie = new blockade.SecureCookie({
  sameSite: { value: "Strict" },
  expires: 1
});

secureCookie.framework(response, "foo", "bar");

Policy Builder

CSP()

Directives: baseUri(sources), blockAllMixedContent(), connectSrc(sources), defaultSrc(sources), fontSrc(sources), formAction(sources), frameAncestors(sources), frameSrc(sources), imgSrc(sources), manifestSrc(sources), mediaSrc(sources), objectSrc(sources), pluginTypes(types), reportTo(json_object), reportUri(uri), requireSriFor(values), sandbox(values), scriptSrc(sources), styleSrc(sources), upgradeInsecureRequests(), workerSrc(sources)

Example:

const cspValue = new blockade.CSP()
  .defaultSrc(blockade.values.none)
  .baseUri(blockade.values.self)
  .blockAllMixedContent()
  .connectSrc(blockade.values.self, "api.spam.com")
  .frameSrc(blockade.values.none)
  .imgSrc(blockade.values, "static.spam.com").value;

// default-src 'none'; base-uri 'self'; block-all-mixed-content; connect-src 'self' api.spam.com; frame-src 'none'; img-src [object Object] static.spam.com

You can check the effectiveness of your CSP Policy at the CSP Evaluator

HSTS()

Directives: includeSubDomains(), maxAge(seconds), preload()

Example:

const hstsValue = new blockade.HSTS()
  .includeSubdomains()
  .preload()
  .maxAge(blockade.seconds.oneMonth).value;

// includeSubDomains; preload; max-age=2592000

XXP()

Directives: disabled() = 0, enabled() = 1, enabledBlock() = 1; mode=block, enabledReport(uri) = 1; report=uri

Example:

 const xxpValue = new blockade.XXP().enabledBlock().value;

// 1; mode=block

XFO()

Directives: allow_from(uri), deny(), sameorigin()

Example:

 const xfoValue = new blockade.XFO().deny().value;

// deny

Referrer()

Directives: noReferrer(), noReferrerWhenDowngrade(), origin(), originWhenCrossOrigin(), sameOrigin(), strictOrigin(), strictOriginWhenCrossOrigin(), unsafeUrl()

Example:

 const referrerValue = new blockade.Referrer().noReferrer().value;

// no-referrer

Feature()

Directives: accelerometer(allowlist), ambient_light_sensor(allowlist), autoplay(allowlist), camera(allowlist), document_domain(allowlist), encrypted_media(allowlist), fullscreen(allowlist), geolocation(allowlist), gyroscope(allowlist), magnetometer(allowlist), microphone(allowlist), midi(allowlist), payment(allowlist), picture_in_picture(allowlist), speaker(allowlist), sync_xhr(allowlist), usb(allowlist), Values(allowlist), vr(allowlist)

Example:

const featureValue = new blockade.Feature()
  .geolocation(blockade.values.self, "spam.com")
  .vibrate(blockade.values.none).value;

// geolocation 'self' spam.com; vibrate 'none'

Cache()

Directives: immutable(), maxAge(seconds), maxStale(seconds), minFresh(seconds), mustRevalidate(), noCache(), noStore(), noTransform(), only_if_cached(), private(), proxyRevalidate(), public(), sMaxage(seconds), staleIfError(seconds), staleWhileRevalidate(seconds),

Example:

const cacheValue = new blockade.Cache()
 .noStore()
 .mustRevalidate()
 .proxyRevalidate().value;

 // no-store, must-revalidate, proxy-revalidate

seconds

Values: fiveMinutes = “300”, oneWeek = “604800”, oneMonth = “2592000”, oneYear = “31536000”, twoYears = “63072000”

values

Values: all = “*”, none = “‘none’”, self = “‘self’”, src = “‘src’”, strictDynamic = “‘strict-dynamic’”, unsafeEval = “‘unsafe-eval’”, unsafeInline = “‘unsafe-inline’”

Usage

Example:

const express = require("express");
const blockade = require("blockade");
const app = express();
const port = 3000;

const cspValue = new blockade.CSP()
  .defaultSrc(blockade.values.none)
  .baseUri(blockade.values.self)
  .blockAllMixedContent()
  .connectSrc(blockade.values.self, "api.spam.com")
  .frameSrc(blockade.values.none)
  .imgSrc(blockade.values, "static.spam.com").value;

const hstsValue = new blockade.HSTS()
  .includeSubdomains()
  .preload()
  .maxAge(blockade.seconds.oneMonth).value;

const xxpValue = new blockade.XXP().enabledBlock().value;

const xfoValue = new blockade.XFO().deny().value;

const referrerValue = new blockade.Referrer().noReferrer().value;

const featureValue = new blockade.Feature()
  .geolocation(blockade.values.self, "spam.com")
  .vibrate(blockade.values.none).value;

const cacheValue = new blockade.Cache()
  .noStore()
  .mustRevalidate()
  .proxyRevalidate().value;

const secureHeaders = new blockade.SecureHeaders({
  csp: cspValue,
  hsts: hstsValue,
  xxp: xxpValue,
  xfo: xfoValue,
  referrer: referrerValue,
  feature: featureValue,
  cache: cacheValue
});

app.use(function(req, res, next) {
  secureHeaders.express(res);
  next();
});

...

Response Headers:

Strict-Transport-Security: includeSubDomains; preload; max-age=2592000
X-Frame-Options: deny
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Content-Security-Policy: default-src 'none'; base-uri 'self'; block-all-mixed-content; connect-src 'self' api.spam.com; frame-src 'none'; img-src [object Object] static.spam.com
Referrer-Policy: no-referrer
Cache-control: no-store, must-revalidate, proxy-revalidate
Feature-Policy: geolocation 'self' spam.com; vibrate 'none'

Supported Frameworks

Framework Agnostic

Return Dictionary of Headers:
secureHeaders.headers()

Example:

const secureHeaders = new blockade.SecureHeaders({ csp: true, feature: true });
return secureHeaders.headers()

Return Value:

{
  'Strict-Transport-Security': 'max-age=63072000; includeSubdomains',
  'X-Frame-Options': 'SAMEORIGIN',
  'X-XSS-Protection': '1; mode=block',
  'X-Content-Type-Options': 'nosniff',
  'Content-Security-Policy': "script-src 'self'; object-src 'self'",
  'Referrer-Policy': 'no-referrer, strict-origin-when-cross-origin',
  Pragma: 'no-cache',
  Expires: '0',
  'Cache-control': 'no-cache, no-store, must-revalidate, max-age=0',
  'Feature-Policy':
   "accelerometer 'none'; ambient-light-sensor 'none'; autoplay 'none'; camera 'none'; encrypted-media 'none'; fullscreen 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; midi 'none'; payment 'none'; picture-in-picture 'none'; speaker 'none'; sync-xhr 'none'; usb 'none'; vr 'none'"
}

AdonisJs

Headers

secureHeaders.adonis(response)

Example:

const blockade = require("blockade");
const secureHeaders = new blockade.SecureHeaders();

class Blockade {
  async handle({ response }, next) {
    secureHeaders.adonis(response);
    await next();
  }
}
module.exports = Blockade;
Cookies
Coookies

ecureCookie.adonis(response, name, value)

Example:

const blockade = require("blockade");
const secureCookie = new blockade.SecureCookie();

. . .

Route.get("/blockade", ({ response }) => {
  secureCookie.adonis(response, "foo", "bar");
  response.send("Blockade");
});

. . .

Express

Headers

secureHeaders.express(res)

Example:

const express = require("express");
const blockade = require("blockade");
const app = express();
const port = 3000;

const secureHeaders = new blockade.SecureHeaders();
. . .

app.use(function(req, res, next) {
  secureHeaders.express(res);
  next();
});

. . .
Cookies

secureCookie.express(res, name, value)

Example:

const express = require("express");
const blockade = require("blockade");
const app = express();
const port = 3000;

const secureCookie = new blockade.SecureCookie();

. . .

app.get("/blockade", function(req, res) {
  secureCookie.express(res, "foo", "bar");
  res.send("blockade");
});

. . .

Fastify

Headers

secureHeaders.fastify(reply)

Example:

const fastify = require("fastify")();

const blockade = require("blockade");
const secureHeaders = new blockade.SecureHeaders();

. . .

fastify.addHook("preHandler", async (request, reply) => {
  secureHeaders.fastify(reply);
});

. . .
Cookies

secureCookie.fastify(reply, name, value)

Example:

const fastify = require("fastify")();

const blockade = require("blockade");
const secureCookie = new blockade.SecureCookie();

. . .

fastify.get("/", function(request, reply) {
  secureCookie.fastify(reply, "foo", "bar");
  reply.send({ blockade: true });
});

. . .

hapi

Headers

secureHeaders.hapi(response)

Example:

const Hapi = require("hapi");
const blockade = require("blockade");

const secureHeaders = new blockade.SecureHeaders();

. . .

server.ext("onPreResponse", (request, h) => {
  const response = request.response;
  secureHeaders.hapi(response);
  return response;
});

. . .
Cookies

secureCookie.hapi(h, name, value)

Example:

const Hapi = require("hapi");
const blockade = require("blockade");

const secureCookie = new blockade.SecureCookie();

. . .

server.route({
  method: "GET",
  path: "/blockade",
  handler: function(request, h) {
    secureCookie.hapi(h, "foo", "bar");
    const response = h.response("blockade");
    return response;
  }
});

. . .

Koa

Headers

secureHeaders.koa(ctx)

Example:

const Koa = require("koa");
const blockade = require("blockade");

const secureHeaders = new blockade.SecureHeaders();
. . .

app.use(async (ctx, next) => {
  await next();
  secureHeaders.koa(ctx);
});

. . .
Cookies

secureCookie.koa(ctx, name, value)

Example:

const Koa = require("koa");
const app = new Koa();
const blockade = require("blockade");

const secureCookie = new blockade.SecureCookie();

. . .

app.use(async ctx => {
  ctx.body = "Blockade";
  secureCookie.koa(ctx, "foo", "bar");
});

. . .

Meteor

Headers

secureHeaders.meteor(res)

Example:

import { Meteor } from "meteor/meteor";
import { SecureHeaders } from "blockade";

const secureHeaders = new SecureHeaders({});

var connectHandler = WebApp.connectHandlers;

Meteor.startup(function() {
  connectHandler.use(function(req, res, next) {
    secureHeaders.meteor(res);
    return next();
  });
});

. . .
Cookies

Meteor does not support cookies naively, please see https://atmospherejs.com/?q=cookie for cookie support packages.

Nest

Headers

secureHeaders.nest(res)

Example:

import { SecureHeaders } from 'blockade';

const secureHeaders = new SecureHeaders({});

export function blockade(req, res, next) {
  secureHeaders.nest(res);
  next();
}
Cookies

secureCookie.nest(res, name, value)

Example:

import { Controller, Get, Post, Res, HttpStatus } from '@nestjs/common';
import { AppService } from './app.service';
import { SecureCookie, SameSite } from 'blockade';
const secureCookie = new SecureCookie({});

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get('blockade')
  getHello(@Res() res): string {
    secureCookie.nest(res, 'foo', 'bar');
    return res.status(HttpStatus.OK).json([]);
  }
}

Polka

Headers

secureHeaders.polka(res)

Example:

const polka = require("polka");
const blockade = require("blockade");
const secureHeaders = new blockade.SecureHeaders();

function headers(req, res, next) {
  secureHeaders.polka(res);
  next();
}

polka()
  .use(headers)
  .get("/", (req, res) => {
    res.end(`Blockade`);
  })
  .listen(3000, err => {
    if (err) throw err;
    console.log(`> Running on localhost:3000`);
  });
Cookies

secureCookie.polka(res, name, value)

Example:

const polka = require("polka");
const blockade = require("blockade");
const secureCookie = new blockade.SecureCookie();

polka()
  .get("/", (req, res) => {
    secureCookie.polka(res, "foo", "bar");
    res.end(`Blockade`);
  })
  .listen(3000, err => {
    if (err) throw err;
    console.log(`> Running on localhost:3000`);
  });

restify

Headers

secureHeaders.restify(res)

Example:

var restify = require("restify");
const blockade = require("blockade");
const secureHeaders = new blockade.SecureHeaders();

function respond(req, res, next) {
  res.send("Blockade");
  next();
}

function headers(req, res, next) {
  secureHeaders.restify(res);
  next();
}

. . .

var server = restify.createServer();
server.pre(headers);
server.get("/", respond);
Cookies

secureCookie.restify(res, name, value)

Example:

var restify = require("restify");
const blockade = require("blockade");
const secureCookie = new blockade.SecureCookie();

function respond(req, res, next) {
  secureCookie.restify(res, "foo", "bar");
  res.send("Blockade");
  next();
}

. . .

var server = restify.createServer();
server.get("/", respond);

Sails

Headers

secureHeaders.sails(res)

Example:

const blockade = require("blockade");
const secureHeaders = new blockade.SecureHeaders();

module.exports.http = {
  middleware: {
    order: ["blockade"],

    blockade: (function() {
      return function(req, res, next) {
        secureHeaders.sails(res);
        return next();
      };
    })()
  }
};
Cookies

secureCookie.sails(res, name, value)

Example:

const blockade = require("blockade");
const secureCookie = new blockade.SecureCookie();

module.exports = {
  blockade: function(req, res) {
    secureCookie.sails(res, "foo", "bar");
    return res.send("Blockade");
  }
};

Total.js

Headers

secureHeaders.total(response)

Example:

const blockade = require("blockade");
const secureHeaders = new blockade.SecureHeaders();

exports.install = function() {
  ROUTE("/", view_index);
};

function view_index() {
  var response = this;
  secureHeaders.total(response);
  response.view("index");
}
Cookies

secureCookie.total(response, name, value)

Example:

const blockade = require("blockade");
const secureCookie = new blockade.SecureCookie();

exports.install = function() {
  ROUTE("/", view_index);
};

function view_index() {
  var response = this;
  secureCookie.total(response, "foo", "bar");
  response.view("index");
}

Resources

Frameworks

  • AdonisJs - NodeJs Web Application Framework. Makes it easy for you to write webapps with less code 😃
  • Express - Fast, unopinionated, minimalist web framework for node.
  • Fastify - Fast and low overhead web framework, for Node.js
  • hapi - Server Framework for Node.js
  • Koa.js - Next generation web framework for Node.js
  • Meteor, - Meteor, the JavaScript App Platform
  • Nest, - A progressive Node.js framework for building efficient and scalable server-side applications on top of TypeScript & JavaScript (ES6, ES7, ES8) heavily inspired by Angular 😻🚀
  • Polka - A micro web server so fast, it’ll make you dance! 👯
  • restify - The future of Node.js REST development
  • Sails, - Realtime MVC Framework for Node.js
  • Total.js - Node.js framework

Indices and tables