Reputation: 243
To have customer accounts more secure, a well crafted password is good practice. This is my Regular Expression string for password validation.
/^(?=.*[0-9])(?!.*?\d{3})(?=.*[a-zA-Z])(?!.*?[a-zA-Z]{3})(?=.*[~!@#$%^&*()+-?])([a-zA-Z0-9~!@#$%^&*()+-?]{8,})$/
Represents:
Having numbers and/or letters in order 3 or more sequential is not OK.
Example:
Not OK = efg123!$, abcd567%, xyz789^&, #hijk23456
OK = ryiiu562@, erty745#, gjnfl45566^
Thank you
Upvotes: 6
Views: 25377
Reputation: 344
If you want to check ascending and descending for both numeric and alpha in the string, then here is a variation on some of the other suggestions:
// Check for three or more sequential alphabetical characters asc/desc
function containsSequentialChars(chars) {
const tests = [chars, chars.split('').reverse().join('')];
for (let ii in tests) {
const s = tests[ii];
for (let i = 0; i < s.length; i++)
if (
String.fromCharCode(s.charCodeAt(i) + 1) === s[+i + 1] &&
String.fromCharCode(s.charCodeAt(i) + 2) === s[+i + 2]
)
return true;
}
return false;
}
// Check for three or more sequential numerical characters asc/desc
function containsSequentialNums(chars) {
const tests = [chars, chars.split('').reverse().join('')];
for (let ii in tests) {
const s = tests[ii];
for (let i = 0; i < s.length; i++)
if (+s[+i + 1] === +s[i] + 1 && +s[+i + 2] === +s[i] + 2) return true;
}
return false;
}
//UNIT TESTS
[
{ fixture: ['aBc', 'cBa', 'AbC', 'CbA'], expect: false },
{ fixture: ['abc', 'cba', 'ABC', 'CBA'], expect: true },
{ fixture: ['12', '21', '312', '1 2 3 4'], expect: false },
{ fixture: ['123', '1234', '321', '4321'], expect: true },
{ fixture: ['aaa123', 'aaa1234', 'aaa321', 'aaa4321'], expect: true },
].forEach((test) => {
test.fixture.forEach((data) => {
const result =
containsSequentialChars(data) || containsSequentialNums(data);
console.log(
test.expect === result ? 'PASS\n' : 'FAIL\n',
'\nexpected',
test.expect,
'\nactual',
result,
'\ndata: ',
data
);
});
});
Upvotes: 0
Reputation: 337
This package is for exactly that: https://github.com/zxcvbn-ts/zxcvbn
zxcvbn is a password strength estimator inspired by password crackers. Through pattern matching and conservative estimation, it recognizes and weighs 40k common passwords, common names surnames, popular words from Wikipedia and common word in different language from different countries, and other common patterns like dates, repeats (aaa), sequences (abcd), keyboard patterns (qwertyuiop), and l33t speak.
Consider using zxcvbn as an algorithmic alternative to password composition policy — it is more secure, flexible, and usable when sites require a minimal complexity score in place of annoying rules like "passwords must contain three of {lower, upper, numbers, symbols}".
More secure: policies often fail both ways, allowing weak passwords (P@ssword1) and disallowing strong passwords. More flexible: zxcvbn allows many password styles to flourish so long as it detects sufficient complexity — passphrases are rated highly given enough uncommon words, keyboard patterns are ranked based on length and number of turns, and capitalization adds more complexity when it's unpredictaBle. More usable: zxcvbn is designed to power simple, rule-free interfaces that give instant feedback. In addition to strength estimation, zxcvbn includes minimal, targeted verbal feedback that can help guide users towards less guessable passwords. For further detail and motivation, please refer to the USENIX Security '16 paper and presentation.
This package also gives feedback on how to strengthen the password, and you can set a required password level.
If you write regular expressions yourself you have to be careful of ReDoS, and you probably won't cover everything either...
Upvotes: 1
Reputation: 1445
To add the descending check based on the answer above;
function test(s) {
// Check for sequential numerical characters
for(var i in s){
if (+s[+i+1] == +s[i]+1 ) return false;
if (+s[+i+1]+1 == +s[i] ) return false;
}
// Check for sequential alphabetical characters
for(var i in s){
if (String.fromCharCode(s.charCodeAt(i)+1) == s[+i+1]) return false;
if (String.fromCharCode(s.charCodeAt(i)-1) == s[+i+1]) return false;
}
return true;
}
// For demo purposes only
var tests = [
'efg123!$',
'abcd567%',
'xyz789^&',
'#hijk23456',
'ryiiu562@',
'erty745#',
'gjnfl45566^',
'2a3b5c6',
'mortz',
'1357911'
], sep = '\t\u2192 ', out = ['Fail','Pass'], eol = '<br>';
document.write('<pre>');
for(var i in tests) document.write(tests[i] + sep + out[+test(tests[i])] + eol);
document.write('</pre>');
Upvotes: 0
Reputation: 12022
You can have a function similar to the below by looping the characters and using a charCodeAt
string method as below.
Note: This is for the question raised in below link as well.
string validation for 3 or more consecutive sequential alphanumeric characters in javascript
function validate() {
var pwd = document.getElementById('password').value;
var isValid = checkPassword(pwd);
var elm = document.getElementById('result');
elm.innerHTML = isValid ? 'Valid' : 'Invalid';
elm.style.color = isValid ? 'green' : 'red';
}
function checkPassword(s) {
if(s) {
var test = (x) => !isNaN(x);
var check = (x, y, i) => x + i === y;
for(var i = 0; i < s.length - 2; i++) {
if(test(s[i])) {
if(test(s[i + 1]) && test(s[i + 2])) {
if(check(Number(s[i]),Number(s[i + 1]), 1) &&
check(Number(s[i]), Number(s[i + 2]), 2)) {
return false;
}
}
} else if(!test(s[i + 1]) && !test(s[i + 2])) {
if(check(s.charCodeAt(i), s.charCodeAt(i + 1), 1) &&
check(s.charCodeAt(i), s.charCodeAt(i + 2), 2)) {
return false;
}
}
}
}
return true;
}
document.getElementById('buttonToValidate').click();
<input type="text" id="password" value="efg123!$" />
<input type="button" id="buttonToValidate" value="Check" onclick="validate()" />
<span id="result" />
Upvotes: 0
Reputation:
There's no way using RegEx that I know of, but here is a naive functional approach.
First, loop through the string and compare each character against the next two characters by adding +1 and +2 to the current index and comparing appropriately.
Second, loop through the string again and compare checks the next two characters against the current character to see if they are sequential.
If both loops fail to find sequential characters, the function returns true, otherwise it returns false.
The first four return false (fail), while the last three return true (pass).
function test(s) {
// Check for sequential numerical characters
for(var i in s)
if (+s[+i+1] == +s[i]+1 &&
+s[+i+2] == +s[i]+2) return false;
// Check for sequential alphabetical characters
for(var i in s)
if (String.fromCharCode(s.charCodeAt(i)+1) == s[+i+1] &&
String.fromCharCode(s.charCodeAt(i)+2) == s[+i+2]) return false;
return true;
}
// For demo purposes only
var tests = [
'efg123!$',
'abcd567%',
'xyz789^&',
'#hijk23456',
'ryiiu562@',
'erty745#',
'gjnfl45566^'
], sep = '\t\u2192 ', out = ['Fail','Pass'], eol = '<br>';
document.write('<pre>');
for(var i in tests) document.write(tests[i] + sep + out[+test(tests[i])] + eol);
document.write('</pre>');
Upvotes: 7