npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

password-hashing-best-practice

v0.0.1

Published

One stop shop for good practice password hashing.

Downloads

3

Readme

password-hashing-best-practice

How exactly should you hash passwords in your Node.js application? Well, you shouldn't reinvent the wheel, and you should try to avoid implementing your own crypto.

This library provdies a single solution for commonly needed methods to use when hashing passwords, with all implementation details abstracted away.

Furthermore, the repository will be home to discussion on how to decide on current best practice, which means that the practice may change, when recommendations for hashing change. If best practice changes, a breaking change of the library will be released.

Contents

  • API and use
  • Method for deciding best practice
  • Current best practice

We are currently pre-1.0, which means the library should be considered unstable. It is probably better than implementing your own crypto, but we don't know the quality of the code. You can find a description of how we will make it to 1.0 in the TODO.

If you wish to contribute, we have a guideline with ideas for how you might do that.

Notice that the project has a Code of Conduct that we expect contributors (of questions, code, tests, documentation, or anything else) to adhere to.

API and use

The package is installed with npm, by running the following command:

npm i password-hashing-best-practice

In your code, you can access the package by requiring it in:

const phbp = require("password-hashing-best-practice");

The current API offers two functions.

Both functions take an optional callback. If no callback is provided, the result will be returned in a Promise instead. Each function has a single result, which may be an object containing several values.

hash

This method simply hashes a password and a salt into a hashed password.

phbp.hash(password[, salt][, callback]);

Inputs.

  • password <string> | <Buffer> | <TypedArray> required. The password to be hashed. If it is a string, it is assumed to be utf8-encoded.
  • salt <string> | <Buffer> | <TypedArray> optional. An optional salt to use for hashing the password. If it is a string, it is assumed to be utf8-encoded. If you want to use another encoding, you should transform it to a Buffer first. If no salt is supplied, a 32 byte random value will be generated and used as salt. In most cases you should leave out the salt. If you need to compare hashed passwords, use the compare function, below.
  • callback <function> optional. A callback function containing the return value (see below) or errors of computing the hash. If it is left out, the result is returned as a Promise instead.

Return value. The function returns an object with two fields:

  • hashedPassword <Buffer>. The result of hashing the password with the salt. This is safe to store in the database.
  • salt <Buffer>. The salt that was used to hash the password. Should likewise be stored in the database, so you can retrieve it to verify passwords in the future.

For example:

let { hashedPassword, salt } = await phbp.hash(password, salt);

... or ...

phbp.hash(password, salt, (error, { hashedPassword, salt }) => {
    if(error) {
        //...
    }
    // ...
});

compare

When a user is logging in, you need to verify that their newly entered password matches the one that belongs to their user account. It is important to use a safe comparison method to avoid timing attacks, which this method implements. You can do this by fetching the hashedPassword and salt that were saved from the user:

phbp.compare(password, salt, hashedPassword[, callback])

Inputs.

  • password <string> | <Buffer> | <TypedArray> required. The new password we want to verify the correctness of.
  • salt <Buffer> required. The salt that was used for creating the hashed password.
  • hashedPassword <Buffer> required. The hashed password that was created when setting the password for the user.
  • callback <function> optional. A callback function containing the return value (see below) or errors of computing the hash. If it is left out, the result is returned as a Promise instead.

Return value. A single <boolean> value, which is true if the password hashed with the salt is the same as the hashed password, and false otherwise.

For example:

if(await phbp.compare(password, salt, hashedPassword)) {
    //Password matches!
}
else {
    //Password does not match.
}

... or ...

phbp.compare(password, salt, hashedPassword, (error, passwordMatches) => {
    if(error) {
        // ...
    }

    if(passwordMatches) {
        //Password matches!
    }
    else {
        //Password does not match.
    }
});

How to handle Buffers

The hashed password and the salt are both returned as Buffers, which may make them hard to store. A simple way of making them easy to store is transforming them to their corresponding hex values, by calling buf.toString("hex"). Before using them in password hashing functions again, you will need to transform them to Buffers again, which can be done with Buffer.from(str, "hex").

For example:

//Given a `password` on user creation...
let { hashedPassword, salt } = await phbp.hash(password);
setUserPassword({
    hashedPasswordHex: hashedPassword.toString("hex"),
    saltHex: salt.toString("hex");
});

// Later, given a new `password` as input from the user...
let { hashedPasswordHex, saltHex } = getUserPassword();
let salt = Buffer.from(saltHex, "hex");
let hashedPassword = Buffer.from(hashedPasswordHex, "hex");

if(await phbp.compare(password, salt, hashedPassword)) {
    //User is authenticated!
}

Method for deciding best practice

  • OWASP, NIST, password-hashing
  • native implementation > module implementation (fast implementation, slow algorithm pls)
  • audit > no audit (which have been audited?)
  • link to ongoing discussion on authorities (stackexchange)

Current best practice

  • According to above evaluation criteria...
  • We have evaluated... (links to evaluation reports)
  • pbkdf2 because it is native and in Node.js (so probably more audited and npm packages?)