From f621c9282c22255d301aee5f51ae24b466978902 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 17 Oct 2023 12:28:46 +0200 Subject: [PATCH] Save bcrypt password checks s in local memory (#6) https://security.stackexchange.com/questions/10520/is-it-safe-or-even-common-to-cache-bcrypt-checks-in-memory/10522#10522 --- README.md | 10 ++++++++-- nodes/http-auth.js | 18 +++++++++++++++++- package-lock.json | 10 +++++----- package.json | 5 ++++- test.sh | 1 + 5 files changed, 35 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 763fd54..a0599a7 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,14 @@ This Node-RED module performs [HTTP Basic authentication](https://developer.mozilla.org/docs/Web/HTTP/Authentication). It is to be used in conjunction with an [HTTP Input node](https://cookbook.nodered.org/http/create-an-http-endpoint). -Supports [bcrypt](https://en.wikipedia.org/wiki/Bcrypt) to store passwords -(such as in the [Apache password format](https://httpd.apache.org/docs/current/misc/password_encryptions.html)). +In other words, it allows putting a password on a Node-RED HTTP listener node. + +Note that this standard protocol sends passwords in plain-text by design, so HTTPS is required to ensure the security of the transmission. + +Supports [bcrypt](https://en.wikipedia.org/wiki/Bcrypt) to store passwords on disc +(such as in the [Apache htpasswd format](https://httpd.apache.org/docs/current/misc/password_encryptions.html)). +Note that this node will cache the bcrypt checks in memory (until the flow is redeployed / restarted) +to improve performance (bcrypt is slow by design, to protect passwords on disc). ## Example diff --git a/nodes/http-auth.js b/nodes/http-auth.js index 8c59c8e..5a38e6f 100644 --- a/nodes/http-auth.js +++ b/nodes/http-auth.js @@ -7,6 +7,12 @@ try { bcrypt = require('bcryptjs'); } +/** + * Cache in local memory the bcrypt decryption (which is very slow by design). + * Reset when the flow is redeployed or restarted. + */ +const bcryptCache = {}; + function passwordCompare(plain, hash) { if (plain == '' || hash == '') { return false; @@ -18,7 +24,17 @@ function passwordCompare(plain, hash) { // Compatibility work-around for 'bcrypt' library hash = hash.replace(/^\$2[x|y]\$/, '$2b$'); - return bcrypt.compareSync(plain, hash); + if (plain === bcryptCache[hash]) { + return true; + } + + const success = bcrypt.compareSync(plain, hash); + + if (success) { + bcryptCache[hash] = plain; + } + + return success; } function basicAuth(authStr, node, msg) { diff --git a/package-lock.json b/package-lock.json index ba0b657..a1a133e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@alexandrainst/node-red-http-basic-auth", - "version": "3.0.0", + "version": "3.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@alexandrainst/node-red-http-basic-auth", - "version": "3.0.0", + "version": "3.1.0", "license": "GPL-2.0", "dependencies": { "bcryptjs": "^2.4.3" @@ -2145,9 +2145,9 @@ } }, "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.0.tgz", + "integrity": "sha512-HQ4J+ic8hKrgIt3mqk6cVOVrW2ozL4KdvHlqpBv9vDYWx9ysAgENAdvy4FoGF+KFdhR7nQTNm5J0ctAeOwn+3g==", "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" diff --git a/package.json b/package.json index df4b9f8..2675625 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@alexandrainst/node-red-http-basic-auth", - "version": "3.0.0", + "version": "3.1.0", "description": "Node-RED node for HTTP Basic Authorization", "keywords": [ "node-red", @@ -9,6 +9,9 @@ "basic", "auth", "authorization", + "access", + "htpasswd", + "password", "rfc2617", "rfc7617" ], diff --git a/test.sh b/test.sh index c15f690..e9f6179 100755 --- a/test.sh +++ b/test.sh @@ -3,6 +3,7 @@ test=$( cat <<'EOF' | node ./index.js http-basic-auth --realm='"node-red"' --username='"test"' --password='"$2y$10$5TSZDldoJ7MxDZdtK/SG2O3cwORqLDhHabYlKX9OsM.W/Z/oLwKW6"' {"req":{"headers":{"authorization":"Basic dGVzdDp0ZXN0"}}} +{"req":{"headers":{"authorization":"Basic dGVzdDp0ZXN0"}}} EOF )