Skip to content

Password Policy Implementation#1611

Open
Zach-O-Bates wants to merge 2 commits into
OpenEnergyDashboard:developmentfrom
Zach-O-Bates:PasswordAuth
Open

Password Policy Implementation#1611
Zach-O-Bates wants to merge 2 commits into
OpenEnergyDashboard:developmentfrom
Zach-O-Bates:PasswordAuth

Conversation

@Zach-O-Bates
Copy link
Copy Markdown

@Zach-O-Bates Zach-O-Bates commented Apr 22, 2026

Description

This pull request resolves issues with password security and inconsistent validation behavior. A uniform password policy is now enforced across user creation and authentication, including minimum length requirements (8 characters for standard users and 14 for administrators), prevention of weak or common passwords using a strength estimator, and disallowing passwords that contain the username. Additionally, this PR addresses bcrypt’s 72-byte limitation by rejecting passwords that exceed this length using a UTF-8 byte check, preventing silent truncation before hashing. Tests were updated to validate both the password policy and truncation protection, ensuring these controls are consistently enforced.

Fixes #1612

Type of change

  • Note merging this changes the database configuration.
  • This change requires a documentation update

Checklist

  • I have followed the OED pull request ideas
  • I have removed text in ( ) from the issue request
  • You acknowledge that every person contributing to this work has signed the OED Contributing License Agreement and each author is listed in the Description section.

Limitations

N/A

@huss
Copy link
Copy Markdown
Member

huss commented Apr 22, 2026

I know @Zach-O-Bates analyzed this package but I wanted to leave a few notes from my looking. Positive is it has > 1M downloads a week and it seems like a decent package for this. Having said that, it does not seem to be maintained even given that not many changes might be needed. The last change was in 2017 and issues/pull requests are not being processed, including ones with security issues. I also saw that they used English to build the model. That is okay but may mean it isn't as good in other languages and OED is internationalized for usage around the world. So, I think it is fine to use this package, esp. compared to doing nothing, but this and any thoughts by others may help with future reconsideration.

Update: I did not try to find a lot of updates but I did find zxcvbn-ts that appears to be currently active. It isn't used as much but something to consider along with other ones that are found.

Copy link
Copy Markdown
Member

@huss huss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Zach-O-Bates Thank you for looking into this. I've made a number of comments. I tried to do a good review but given the possible changes that may be made, other thoughts may come at a later time. I also only did minimal testing at this point. Please let me know if anything is not clear, you have thoughts/questions or I can help.

@@ -0,0 +1,66 @@
const { chai, mocha, app } = require('../common');
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This and the other new file are missing the copyright notice.

@@ -0,0 +1,33 @@
const zxcvbn = require('zxcvbn');
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it might be good to put a TODO linking to https://github.com/dropbox/zxcvbn#script-load-latency. This isn't huge (400k) but it isn't trivial either. OED hopes to make a future effort to reduce the bundle size and these ideas might help. It might also be good to note that at this time it isn't used on the client.

Comment thread src/server/util/validatePassword.js Outdated
@@ -0,0 +1,33 @@
const zxcvbn = require('zxcvbn');

//Temproarly list, until we decide a better approach like a specific file
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spelling: Temproarly. Also, I think this should be a TODO as an action is needed. It also might be nice to say what a good list would contain.


//Temproarly list, until we decide a better approach like a specific file
const COMMON_PASSWORDS = new Set([
'password',
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Space intending instead of tab. Same in other file.

'12345678',
]);

function validatePasswordPolicy(password, username, role = []) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JSDoc would be good.

I see where this is used in src/server/routes/users.js for /create. I'm wondering about all the other places where passwords are entered: Same route in /edit, src/server/services/user/createUser.js & src/server/services/user/editUser.js. Also, this could be used on the front-end to give feedback without contacting the server but that would mean putting this into the client bundle and this isn't done very often so I'm okay with not doing that now (or maybe ever).


});

const chaiHttp = require('chai-http');
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OED prefers all require/include at the top of a file.


let adminToken;

mocha.before(async () => {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indenting off.

const res = await chai.request(app)
.post('/api/login')
.send({
username: 'test@example.invalid',
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This really should use testUser to get the info as in other tests.

adminToken = res.body.token;
});

mocha.it('Rejects weak password on create', async () => {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These will need to be expanded if other routes are used during password testing per another comment.

bcrypt from silently truncating the password before hashing */
const byteLength = Buffer.byteLength(password, 'utf8');
if (byteLength > 72) {
return res.status(400).send({ message: 'Password must not exceed 72 bytes.' });
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the numeric values are being replaced by constants. Thus, this should happen when PR 1581 is merged.

I also think the message could be more user friendly. Maybe "Password must not exceed 72 bytes which often means 72 characters."

@huss
Copy link
Copy Markdown
Member

huss commented Apr 22, 2026

I also forgot to add this: How will current site passwords be handled that do not meet the new standards? Do they need to be reentered or do they just stay until updated? If forcing to reenter then how should that be done? Any thoughts?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Passwords longer than 72 bytes are silently truncated

2 participants