JavaScript
Article
By Christopher Pitt

You Don’t Know Jacks: Learn to Make Your Code More Secure

By Christopher Pitt

This article was sponsored by Codiscope. Thank you for supporting the sponsors who make SitePoint possible.

I used to play a game called You Don’t Know Jack. It’s a trivia game, set as a game show, in which it’s fun to lose. Upon giving an incorrect answer, the player is treated to a witty and irreverent reprimand from the game’s host.

It’s also an abject lesson in how little details mean the difference between getting something right and getting something horribly, embarrassingly wrong.

Recently, I was asked to write about Jacks. I’d never heard of it before, but it was immediately interesting to me. You see, there aren’t many services that claim to help you as you learn about how to code securely. Jacks wants to be that service. Almost like a coach. That never sleeps. And costs nothing.

Unlike the trivia game, it’s more forgiving. That’s great when you really don’t know what you’re doing — as I found out when I decided to learn a new web framework.

Most of the code for this post can be found on Github . I’ve tested it in Node 7.0.0, on macOS Sierra 10.12.1.

Getting Hapi

I’ve written many little NodeJS applications, and I’ve often found Express to be just enough for my web application needs. But I’ve also wondered how best to structure a much larger application. There are opinionated options, like Adonis, but I’m already quite familiar with it. What new thing could I learn, while also kicking Jacks’ tires?

And then I saw mention of Hapi on Jacks’ home page .

I opened my terminal, made a new project folder, and installed Hapi:

yarn add hapi

You can also install Hapi using NPM. I’m just a sucker for trends, and Yarn is pretty darn fast!

According to the docs, making a Hapi application is as easy as:

"use strict"

const hapi = require("hapi")

const server = new hapi.Server()

server.connection({
    "port": 3000,
})

server.route({
    "method": "get", "path": "/",
    handler: function (request, reply) {
        reply("hello world")
    },
})

server.start(err => {
    if (err) {
        throw err
    }

    console.log("server at " + server.info.uri)
})

This is from index.js.

If you’ve used Express, this should look somewhat familiar to you. I’ve created a new HTTP server, with a single route. When a browser requests /, this route will reply with hello world:

Hello world

Plugging In

The next step was to connect my Github account to Jacks. Creating a Jacks account was rather effortless, and free. First I set up a new project:

Creating a new project

…and then I connected my Github account (and the project repository) to Jacks:

Connect to Jacks

This all took about 2 minutes, from start to finish.

--ADVERTISEMENT--

Making Mistakes

Now it was time to see just how helpful Jacks could be. I got together a list of common web app security mistakes, and decided to try a few, to see what Jacks would say (and how it could teach me to be better at my job).

Content Security Policy

At this point, I wasn’t expecting Jacks to have any recommendations for me yet. But, when I went back to the interface, I saw the first bit of advice it had to offer me:

CSP recommendation

It took a bit of searching for a good explanation, but I finally found one at Content Security Policy CSP Reference & Examples. CSP is essentially a way of restricting where HTTP resources may be loaded from. This is great because malicious users who might have been able to inject custom scripts and/or images wouldn’t be able to exploit those vulnerabilities as easily.

Jacks also provided example code for how to add Blankie to my server script:

"use strict"

const hapi = require("hapi")
const blankie = require("blankie")
const scooter = require("scooter")

const server = new hapi.Server()

// ...create server + connection + routes

server.register([scooter, {
    "register": blankie,
    "options": {
        // ..CSP directives here
        "defaultSrc": "self",
    }
}], err => {
    // ...start server
})

This is from index.js.

I needed to install Blankie and Scooter, with yarn add blankie and yarn add scooter, for this code to work. These add CSP headers to each request:

CSP headers

Sure enough, as soon as I committed that code to the project, Jacks noticed it and marked the recommendation as resolved.

Disabling Directory Listings

A common security pitfall is enabling (or rather not appropriately disabling) directory listings in web apps. There’s a popular Hapi plugin, called Inert, which enables static file serving and directory listings. It’s not uncommon to enable these features, so that’s what I tried to do:

"use strict"

const hapi = require("hapi")
const blankie = require("blankie")
const scooter = require("scooter")
const inert = require("inert")

// ...create server + connection

server.register([inert, scooter, {
    "register": blankie,
    "options": {
        // ..CSP directives here
        "defaultSrc": "self",
    }
}], err => {
    // ...create other routes

    server.route({
        "method": "GET", "path": "/{params*}",
        "handler": {
            "directory": {
                "path": "public",
                "listing": true,
            },
        },
    })

    // ...start server
})

This is from index.js.

I needed to install Inert, with yarn add inert, for this code to work. Once I did, I was able to see directory listings in y web app:

Directory listing

I committed this code to the repository, and hopped over to Jacks for an analysis. As expected, it warned against enabling directory listings:

Directory listing warning

What’s more, it provided me with patch information, to disable directory listings:

Directory listing patch

That’s pretty great for Hapi beginners, like me. Once I followed this advice, Jacks stopped warning me about this particular problem.

Insecure Cookies

The final security hole I wanted to test was insecure session/state management. The Hapi docs show how to create cookies, to store session state. They mention the various settings you could use, and what their defaults are. What they don’t mention is how you can botch session security, using the wrong settings:

"use strict"

const hapi = require("hapi")
const blankie = require("blankie")
const scooter = require("scooter")
const inert = require("inert")

// ...create server + connection

server.register([inert, scooter, {
    "register": blankie,
    "options": {
        // ..CSP directives here
        "defaultSrc": "self",
    }
}], err => {
    server.state("session", {
        "ttl": 24 * 60 * 60 * 1000,
        "isSecure": false,
        "isHttpOnly": false,
        "path": "/",
        "encoding": "base64json",
    })

    server.route({
        "method": "get", "path": "/",
        handler: function (request, reply) {
            let session = request.state.session

            if (!session) {
                session = {
                    "returning": true
                }
            }

            session.date = Date.now()

            return reply("hello world")
                .state("session", session)
        },
    })

    // ...create other routes
    // ...start server
})

This is from index.js.

At this point I expected Jacks to point out the offending lines of code:

"isSecure": false,
"isHttpOnly": false,

Those don’t look very secure to me, and they also deviate from the Hapi default values. I guess that goes to show that even though human code evaluation may reveal obvious-looking errors, it’s much harder to make an algorithm see them.

Other Things Jacks Protects Against

I got in contact with the Jacks developers, and they told me about many other things Jacks recommends:

  • Using adaptive one-way hashing functions to store passwords
  • Using methods other than HTTP basic auth (over HTTPS)
  • Using appropriate work factors with PBKDF2 and Scrypt
  • Using CSPRNG appropriately
  • Enabling CORS whitelisting
  • Avoiding JSONP Rosetta Flash vulnerability

…And these are just some of the recommendations specific to Hapi. Jacks can also analyze MongoDB and Express code. Recently they also added Java support, beginning with Spring and Struts .

Conclusion

I’m definitely keen to keep on using Jacks as I learn more about Hapi. It’s just the kind of help I need as I code. And when I get stuck, I can always use the instant support messaging feature to speak to one of their developers. Best of all, it’s free.

Recommended
Sponsors
Get the latest in JavaScript, once a week, for free.