Coder Social home page Coder Social logo

simonepri / upash Goto Github PK

View Code? Open in Web Editor NEW
532.0 12.0 24.0 512 KB

๐Ÿ”’Unified API for password hashing algorithms

Home Page: https://www.npmjs.com/upash

License: MIT License

JavaScript 100.00%
credential nodejs hash-functions security brute-force timing-attacks rainbow-table bcrypt pbkdf2 argon

upash's Introduction

upash

Mac/Linux Build Status Windows Build status Codecov Coverage report Known Vulnerabilities Dependency Status
XO Code Style used AVA Test Runner used Istanbul Test Coverage used NI Scaffolding System used NP Release System used
Mentioned in Awesome NodeJS Latest version on npm Project license

๐Ÿ”’ Unified API for PASsword Hashing algorithms
Coded with โค๏ธ by Simone Primarosa.

Synopsis

Password breaches have become more and more frequent.
See: Yahoo (twice), LinkedIn, Adobe, Ashley Madison, and a whole lot more.

Indeed, the above examples doubles as a list of "how NOT to do password storage": simple hashing, unsalted values, misuse of encryption, and failed password migration. (For more information on why these are bad, see our introduction to password hashing theory)

There are two possible interpretations here: first, companies do not put adequate resources in securing passwords; and secondly, getting password hashing right is hard. Furthermore, even if you have followed previous best practice, keeping it right is another technical challenge: algorithm choices, security levels, parameter selection change regularly.

Make passwords painless

upash api

The upash (pronounced u-pash) project aims is to allow you to have a clean and easy-to-use API to use any password hashing algorithm seamlessly in your application.


Highlights

Do you believe that this is useful? Has it saved you time? Or maybe you simply like it?
If so, support my work with a Star โญ๏ธ and follow me ๐Ÿ“ฉ.

Usage

The upash solution is straight-forward but it is important to follow all the steps carefully.

Firstly, you need to install this package.

npm install --save upash

Then, you need to choose from the list of supported password hashing algorithms the one that best suits your needs and install that too.
In the following, we will assume that you choose @phc/argon2, that is also a suitable solution in case you don't know which one fits better for you.

npm install --save @phc/argon2

Finally, you can enjoy the easy APIs.

const upash = require('upash');

// Install the algorithm of your choice.
upash.install('argon2', require('@phc/argon2'));

// Hash API
const hashstr = await upash.hash('password');
// => "$argon2id$v=19$m=4096,t=3,p=1$PcEZHj1maR/+ZQynyJHWZg$2jEN4xcww7CYp1jakZB1rxbYsZ55XH2HgjYRtdZtubI"

// Verify API
const match = await upash.verify(hashstr, 'password');
// => true

You can store the hash returned by the hash function directly into your database.

You can also install more than one algorithm at once.
This is really handy when you want to update your current password hashing algorithm.

const upash = require('upash');

// Install the algorithms of your choice.
upash.install('pbkdf2', require('@phc/pbkdf2'));
upash.install('argon2', require('@phc/argon2'));

// You can explicitly tell upash which algorithm to use.
const hashstr_pbkdf2 = await upash.use('pbkdf2').hash('password');
// => "$pbkdf2-sha512$i=10000$O484sW7giRw+nt5WVnp15w$jEUMVZ9adB+63ko/8Dr9oB1jWdndpVVQ65xRlT+tA1GTKcJ7BWlTjdaiILzZAhIPEtgTImKvbgnu8TS/ZrjKgA"

// If you don't do so it will automatically use the last one installed.
const hashstr_argon2 = await upash.hash('password');
// => "$argon2i$v=19$m=4096,t=3,p=1$mTFYKhlcxmjS/v6Y8aEd5g$IKGY+vj0MdezVEKHQ9bvjpROoR5HPun5/AUCjQrHSIs"

// When you verify upash will automatically choose the algorithm to use based
// on the identifier contained in the hash string.
const match_pbkdf2 = await upash.verify(hashstr_pbkdf2, 'password');
// => true

// This will allow you to easily migrate from an algorithm to another.
const match_argon2 = await upash.verify(hashstr_argon2, 'password');
// => true

Recommended algorithms implementations

The following is a curated list of algorithms that adhere to the upash APIs guidelines and are ready to work at a production level straight out of the box.
All the functions come pre-configured but fine-tuning is always a good practice.
The defaults are maintained by the community and the aim of this project is also to bring together experts to be able to provide you reasonably secure default configurations.

Packages that are implemented natively (Node.js only)

  • @phc/argon2 - ๐Ÿ”’ Node.JS argon2 password hashing algorithm following the PHC string format.
  • @phc/pbkdf2 - ๐Ÿ”’ Node.JS pbkdf2 password hashing algorithm following the PHC string format.
  • @phc/scrypt - ๐Ÿ”’ Node.JS scrypt password hashing algorithm following the PHC string format.
  • @phc/bcrypt - ๐Ÿ”’ Node.JS bcrypt password hashing algorithm following the PHC string format.

Packages that are implemented in JavaScript (Browser compatible)

  • WIP

If you wanna help me with these DM me on twitter.

Packages that are implemented in WebAssembly (Browser compatible)

  • WIP

If you wanna help me with these DM me on twitter.

Want your package listed here? Open an issue and we will review it.

Test configurations through the CLI

upash cli

Generally, each function allows configuration of 'work factorsโ€™. Underlying mechanisms used to achieve irreversibility and govern work factors (such as time, space, and parallelism) vary between functions.

You want to adjust the work factor to keep pace with threats' increasing hardware capabilities so as to impede attackers while providing acceptable user experience and scale.

A common rule of thumb for tuning the work factor (or cost) is to make the function run as slow as possible without affecting the users' experience and without increasing the need for extra hardware over budget.

The CLI lets you hash and verify password directly from your terminal.
You can use it to test work, memory and parallelism parameters on different machines.

For installation and usage information about the CLI, see the upash-cli page.

Migrating your existing password hashing solution

If you are not building a new application, chances are high that you have already implemented some hash/verify logic for your passwords.
The migration guide provides some good guidance on how to accomplish an upgrade in place without adversely affecting existing user accounts and future proofing your upgrade so you can seamlessly upgrade again (which you eventually will need to do).

Please if you do not find a migration documentation that fits your case, open an issue.

Upgrading your password hashing algorithm

Upgrading the hashing algorithm used to hash passwords inside your application can be a really painful operation if not done well. You should take a lot of attention in order to not adversely affect existing user accounts.

This article is a nice start that should give you some ideas on what are the problems related to that process.

Example of implementations can be found in the upgrade algorithm guide.

API

install(name, algorithm)

Installs a compatible password hashing function.

uninstall(name)

Uninstalls a password hashing function previously installed.

list() โ‡’ Array.<string>

Gets the list of the installed password hashing functions.

use(name) โ‡’ Object

Selects manually which password hashing function to use. You can call hash and verify on the object returned.

which(hashstr) โ‡’ string | null

Returns the name of the algorithm that has generated the hash string.

verify(hashstr, password) โ‡’ Promise.<boolean>

Determines whether or not the hash provided matches the hash generated for the given password choosing the right algorithm based on the identifier contained in the hash.

hash(password, [options]) โ‡’ Promise.<string>

Computes the hash string of the given password using the 'last' algorithm installed.

install(name, algorithm)

Installs a compatible password hashing function.

Kind: global function
Access: public

Param Type Description
name string The name of the password hashing function.
algorithm Object The password hashing function object.
algorithm.hash function A function that takes a password and returns a cryptographically secure password hash string.
algorithm.verify function A function that takes a secure password hash string and a password and returns whether or not the password is valid for the given hash string.
algorithm.identifiers function A function that returns the list of identifiers that this password hashing algorithm is able to generate / verify.

uninstall(name)

Uninstalls a password hashing function previously installed.

Kind: global function
Access: public

Param Type Description
name string The name of the algorithm to uninstall or 'last' to uninstall the last one installed.

list() โ‡’ Array.<string>

Gets the list of the installed password hashing functions.

Kind: global function
Returns: Array.<string> - The array of the available password hashing functions.
Access: public

use(name) โ‡’ Object

Selects manually which password hashing function to use. You can call hash and verify on the object returned.

Kind: global function
Returns: Object - The password hashing function object.
Access: public

Param Type Description
name string | undefined The name of the algorithm to use.

which(hashstr) โ‡’ string | null

Returns the name of the algorithm that has generated the hash string.

Kind: global function
Returns: string | null - The name of password hashing algorithm.
Access: public

Param Type Description
hashstr string Secure hash string generated from this package.

verify(hashstr, password) โ‡’ Promise.<boolean>

Determines whether or not the hash provided matches the hash generated for the given password choosing the right algorithm based on the identifier contained in the hash.

Kind: global function
Returns: Promise.<boolean> - A boolean that is true if the hash computed for the password matches.
Access: public

Param Type Description
hashstr string Secure hash string generated from this package.
password string User's password input.

hash(password, [options]) โ‡’ Promise.<string>

Computes the hash string of the given password using the 'last' algorithm installed.

Kind: global function
Returns: Promise.<string> - The generated secure hash string.
Access: public

Param Type Description
password string The password to hash.
[options] Object Optional configurations related to the hashing function. See the algorithm specific documentation for the options supported.

Contributing

Contributions are REALLY welcome and if you find a security flaw in this code, PLEASE report it.

Authors

See also the list of contributors who participated in this project.

License

This project is licensed under the MIT License - see the license file for details.

upash's People

Contributors

elderapo avatar simonepri 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

upash's Issues

Can support CRYPT_BLOWFISH

Use the CRYPT_BLOWFISH algorithm to create the hash. This will produce a standard crypt() compatible hash using the "$2y$" identifier.

like php

typescript definition

please add typescript definition

currently i made a custom one in my own project using upash. If it can help:

/// <reference types="node" />

declare module "upash" {
    type PHCstring = string;

    namespace Upash {
        /**
         * Installs a compatible password hashing function.
         */
        function install(
            name: string,
            algorithm: {
                hash(
                    password: string,
                    options?: { [key: string]: any }
                ): Promise<PHCstring>;
                verify(
                    phcString: PHCstring,
                    password: string
                ): Promise<boolean>;
            }
        ): void;

        /**
         * Gets the list of the installed password hashing functions.
         */
        function list(): string[];

        /**
         * Uninstalls a password hashing function previously installed.
         */
        function uninstall(name: string): void;

        /**
         * Selects manually which password hashing function to use. You can call hash and verify on the object returned.
         */
        function use(
            name: string
        ): {
            hash: typeof hash;
            verify: typeof verify;
        };

        /**
         * Returns the name of the algorithm that has generated the hash string.
         */
        function which(name: PHCstring): string;

        /**
         * Computes the hash string of the given password in the PHC format using argon2 package.
         * @returns a hash with the PHC string format (see https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md)
         */
        function hash(
            password: string,
            options?: { [key: string]: any }
        ): Promise<PHCstring>;

        /**
         * Determines whether or not the hash stored inside the PHC formatted string matches the hash generated for the password provided.
         */
        function verify(
            phcString: PHCstring,
            password: string
        ): Promise<boolean>;
    }

    export = Upash;
}

No valid versions available for @upash/universal

I'm submitting a

  • [x ] bug report
  • feature request
  • support request => Please do not submit support request here, see note at the top of this template.

Checklist

  • [x ] Searched both open and closed issues for duplicates of this issue
  • [x ] Title adequately and concisely reflects the feature or the bug

##ย Information

I'm no longer able to update or install package through npm. I was able to install this a couple months ago. Is this project now defunct?

git:(master) โœ— npm install --save @upash/universal
npm ERR! code ENOVERSIONS
npm ERR! No valid versions available for @upash/universal

Can this work in AWS lambda functions?

I can't seem to get the simple example to work in AWS lambda function. Appears to error on the upash.install line. Here is my function...

const upash = require('upash');
upash.install('argon2', require('@phc/argon2'));

exports.handler = function (event, context, callback) {
	try {
		console.log('===> body: ', event.body);
		const hp = event.body.split('&');
		const handle = hp[1].split('=')[1];
		const pass = hp[0].split('=')[1];
		console.log('===> handle: ', handle);
		console.log('===> pass: ', pass);
		(async () => {
			const hashstr = await upash.hash(pass);
			callback(null, {
				statusCode: 200,
				body: JSON.stringify({ hashstr })
			});
		})();
	} catch (error) {
		callback(null, {
			statusCode: 500,
			body: JSON.stringify(error)
		});
	}
};

If you move the upash.install inside the handler, the code will run up until it hits the upash.install line then the function errors (with a blank error message) at that point. So this is some kind of hard/can't-handle crash on that line when running in lambda functions

With the upash.installl line above/outside the function (like the code shows) you get a 'path' error...

Request from ::1: POST /gen-hash
Response with status 500 in 4 ms.
Error during invocation: TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string
at assertPath (path.js:39:11)
at dirname (path.js:714:5)
at Function.r.getRoot (C:\Users\markd\Documents\code-projects\web\netlify\easy-message-bus-netlify-restapi\lambda\gen-hash.js:1:10807)
at r (C:\Users\markd\Documents\code-projects\web\netlify\easy-message-bus-netlify-restapi\lambda\gen-hash.js:1:10003)
at Object.117 (C:\Users\markd\Documents\code-projects\web\netlify\easy-message-bus-netlify-restapi\lambda\gen-hash.js:1:7659)
at t (C:\Users\markd\Documents\code-projects\web\netlify\easy-message-bus-netlify-restapi\lambda\gen-hash.js:1:220)
at Object.116 (C:\Users\markd\Documents\code-projects\web\netlify\easy-message-bus-netlify-restapi\lambda\gen-hash.js:1:3959)
at t (C:\Users\markd\Documents\code-projects\web\netlify\easy-message-bus-netlify-restapi\lambda\gen-hash.js:1:220)
at Object.135 (C:\Users\markd\Documents\code-projects\web\netlify\easy-message-bus-netlify-restapi\lambda\gen-hash.js:1:19423)
at t (C:\Users\markd\Documents\code-projects\web\netlify\easy-message-bus-netlify-restapi\lambda\gen-hash.js:1:220)
at C:\Users\markd\Documents\code-projects\web\netlify\easy-message-bus-netlify-restapi\lambda\gen-hash.js:1:1019
at Object. (C:\Users\markd\Documents\code-projects\web\netlify\easy-message-bus-netlify-restapi\lambda\gen-hash.js:1:1030)
at Module._compile (module.js:662:30)
at Object.Module._extensions..js (module.js:673:10)
at Module.load (module.js:575:32)
at tryModuleLoad (module.js:515:12)

API Improvment

Description

Expose a constructor to allow the users to have multiple instance of upash instead of having it as a singleton.

Examples

const UPASH = require('upash');

// Create an instance of upash providing the algorithms of your choice.
const upash = new UPASH({
  argon2: require('@phc/argon2'),
  pbkdf2: require('@phc/pbkdf2')
}, {default: 'argon2'});

// You can explicitly tell upash which algorithm to use.
const hashstr_pbkdf2 = await upash.use('pbkdf2').hash('password');
// => "$pbkdf2-sha512$i=10000$O484sW7giRw+nt5WVnp15w$jEUMVZ9adB+63ko/8Dr9oB1jWdndpVVQ65xRlT+tA1GTKcJ7BWlTjdaiILzZAhIPEtgTImKvbgnu8TS/ZrjKgA"

// If you don't do so it will automatically use the default one.
const hashstr_argon2 = await upash.hash('password');
// => "$argon2i$v=19$m=4096,t=3,p=1$mTFYKhlcxmjS/v6Y8aEd5g$IKGY+vj0MdezVEKHQ9bvjpROoR5HPun5/AUCjQrHSIs"

// When you verify upash will automatically choose the algorithm to use based
// on the identifier contained in the hash string.
const match_pbkdf2 = await upash.verify(hashstr_pbkdf2, 'password');
// => true

// This will allow you to easily migrate from an algorithm to another.
const match_argon2 = await upash.verify(hashstr_argon2, 'password');
// => true

Notes

Probably it makes sense to remove install and uninstall methods and add a getDefault method.
This would lead to a breaking change.

cc @mcollina

Adding support for needsRehash

First of all, it is a great, well written project. Thanks ๐Ÿ™

Since uphash has the params and version information, I was thinking, if we should add support for needsRehash function, that returns a boolean, if the config values are different from the encoded values. PHP already does the same.

Ideally the function will be added to the underlying libraries @phc/bcrypt, @phc/argon2 and I am happy to work on the PR, if you think we should add it

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.