Jump to content
sKunKbad

Require digits, but not necessarily together

Recommended Posts

I'm playing around with some regex that is used for password strength, and right not it ensures that there is at least one digit:

/^(?=.*\d).*$/

This works great, but I was thinking what if I wanted to say that more than 1 digit was required, so I tried this:

/^(?=.*\d{2,}).*$/

This works only if the two digits are next to each other:

exam22ple // match
exam2pl2e // does not match

So, what I'd like to know is how to match when the digits are not next to each other.

Share this post


Link to post
Share on other sites

First off: Password rules suck. Unless you're contractually obliged to implement this, just don't. Not only is the security benefit highly questionable; it can be downright counter-productive to enforce a specific pattern, because this leads to problems with purely random passwords (which are in fact the strongest possible choice). For example, I generate and store my passwords with a password manager. If you enforce a certain number of digits, special characters and whatnot, I have to do a lot of extra work and maybe even weaken the password only to make the validator happy. That obviously makes no sense.

 

A far better solution is to provide a password strength estimator and point your users to password managers. Inexperienced users will get positive feedback and may actually learn something, experienced users have a chance to opt out of the procedure.

 

If you absolutely must implement a password policy, do it with code. Sure, we can give you a long, cryptic regex for your rules, but if even you cannot understand it, why on earth would you want it in your code?

<?php

// Just say no
$regex = '/\\d\\D*\\d/';
var_dump(preg_match($regex, 'exam22ple'));
var_dump(preg_match($regex, 'exam2pl2e'));
  • Like 1

Share this post


Link to post
Share on other sites

First off: Password rules suck. Unless you're contractually obliged to implement this, just don't. Not only is the security benefit highly questionable; it can be downright counter-productive to enforce a specific pattern, because this leads to problems with purely random passwords (which are in fact the strongest possible choice).

Purely random passwords will probably already contain mixed letters, digits, and symbols, so they meet nearly all password requirements already. But surely you recognize that you're in the vast minority of users: a typical person will use a word or two plus a couple numbers as required by the system, and will not have something that creates and remembers passwords for them.

 

Yeah, users may not like password rules, but (a) they're getting used to them and (b) whether they realize it or not they would rather have a more complicated password than have their account compromised.

 

If you enforce a certain number of digits, special characters and whatnot, I have to do a lot of extra work and maybe even weaken the password only to make the validator happy. That obviously makes no sense.

I assume your passwords already contain at least one of everything, right? Uppercase letter, lowercase letter, number, and symbol. If not then they're not as secure as they could be, and I know you hate when stuff isn't as secure as it could be. So there shouldn't be any problem with that. Length is the only other requirement, but it's almost always just minimum length and I can't imagine your passwords being less than 8 characters long - the most common minimum length.

 

Stuff like a maximum length, or "no more than N" types of characters, and certainly not "may not contain any of X" symbols (not counting, like, not containing a name or username) is bad and should not be used. Naturally. I assume we're not talking about those.

 

What makes no sense is why your random passwords would be not secure enough to meet a site's good password requirements, and why altering your rules to fit those requirements would make them weaker.

 

Fun fact: Passwords used by Visa's "Verified By Visa" program have to be, like,

 

A far better solution is to provide a password strength estimator and point your users to password managers. Inexperienced users will get positive feedback and may actually learn something, experienced users have a chance to opt out of the procedure.

Inexperienced users will wonder what they have to do to make the bar go green, get longer, or do whatever, so some mention of guidelines is good. But if someone is registering with an important system - say, their bank - simply encouraging them to use a strong password may not be sufficient.

 

A red meter tells me that my password of "lincoln15" sucks but doesn't actually make me do anything about it. Password constraints exist to make sure people pick technically-secure passwords. They don't always have to be used, opting for the strength meter or a mere list of guidelines instead, but sometimes they should be.

Share this post


Link to post
Share on other sites

Well, what I was trying to achieve is a config file that has a bunch of rules that are used to dynamically create regex for the validation of password strength, and turning this off completely would be an option. I only got this idea because I've been watching some videos on regex. Even though I've been tinkering with regex for years, it's just not something I'm good at. So, while looking at the existing regex I've been using for password strength, I wondered how I would force somebody to have more than one digit, say 2 or 3 or 50. It was just a thought.

Share this post


Link to post
Share on other sites

I found this works:

/^(?=(?:.*[\d].*){3,}).*$/

I can change the 3 to whatever number I want, and seems to match appropriately.

Share this post


Link to post
Share on other sites

Why does something like this need to be in a configuration file? Requiring some specific number of digits is silly, and making that variable seems even sillier. Passwords should contain at least one digit - isn't an option to enforce that sufficient?

Share this post


Link to post
Share on other sites

Forget about passwords. I told ya I'm just learning, and I'm just using passwords because it's Sunday and I'm too lazy to come up with something else on my day off.

 

So, I found an answer, but while I understand the basics of what a positive lookahead is, I guess my next question would be if I'm not needing a capturing group, does it hurt performance or anything if it is capturing vs non-capturing?

// This
/^(?=(?:.*[\d].*){3,}).*$/

// Works the same as this
/^(?=(.*[\d].*){3,}).*$/

In the end preg_match is going to give me a boolean and I'm not using the matches parameter at all.

 

PS. While it might seem silly, I've had customers ask me to enforce passwords that were 5 alphas and 3 numbers. It happens.

Edited by sKunKbad

Share this post


Link to post
Share on other sites

I guess my next question would be if I'm not needing a capturing group, does it hurt performance or anything if it is capturing vs non-capturing?

While I've not done any testing, I would assume that using non-capturing groups would be slightly better. However I doubt the difference between the two is worth worrying about unless you're running a particular expression many times in a loop.

 

PS. While it might seem silly, I've had customers ask me to enforce passwords that were 5 alphas and 3 numbers. It happens.

As a developer, you should inform them that such arbitrary rules are silly and they are doing their uses a disservice. For the last few projects I've worked on I've take the route of using a minimum length + 3 of 5 basic checks. Those checks being:

  • One or more lower case letters
  • One or more upper case letters
  • One or more digits
  • One or more special characters
  • Length of 15 characters or more.
It provides a reasonable amount of flexibility while also helping to prevent the use of simple passwords.
  • Like 1

Share this post


Link to post
Share on other sites

So you're here to practice wrong solutions for hypothetical problems so that you can please stupid customers? Good lord.

 

But thanks for reminding me that I have better things to do on a Sunday.

Share this post


Link to post
Share on other sites

One last thing: Password policies exist to make corporate bureaucracy happy and provide a legal cop-out for incompetent superiors. A developer should understand that.

 

The idea that users will make smart decisions if you bombard them with stupid rules and then beat them into submission is just silly. Does any of you function like that? When I encounter one of those security-by-bureaucracy forms, it makes me want to punch the site owners in the face, and I won't do anything but the bare minimum to escape the procedure. In other words, instead of shitty passwords with less than two digits, you now get shitty passwords with at least two digits. Congratulations.

 

If you want actual security, you have to work with the user. Coming up with arbitary rules and telling people that password security is now their problem doesn't work. You need to provide incentives and realistic solutions. No password policy has ever made me choose better passwords. But a single link to KeePass did convince me.

 

 

 

Purely random passwords will probably already contain mixed letters, digits, and symbols, so they meet nearly all password requirements already.

 

It's impossible to cover all absurd rules people come up with.

 

If you use symbols, they aren't permitted. If you don't use symbols, they're required. If you use long passwords, they're too long, If you use short passwords, they're too short. And then of course everybody has their favorite characters and pet theories about password strength.

 

It's just annoying. It's one of those stupid traditions which never seems to die.

Edited by Jacques1
  • Like 1

Share this post


Link to post
Share on other sites

One last thing: Password policies exist to make corporate bureaucracy happy and provide a legal cop-out for incompetent superiors. A developer should understand that.

 

The idea that users will make smart decisions if you bombard them with stupid rules and then beat them into submission is just silly. Does any of you function like that? When I encounter one of those security-by-bureaucracy forms, it makes me want to punch the site owners in the face, and I won't do anything but the bare minimum to escape the procedure. In other words, instead of shitty passwords with less than two digits, you now get shitty passwords with at least two digits. Congratulations.

 

If you want actual security, you have to work with the user. Coming up with arbitary rules and telling people that password security is now their problem doesn't work. You need to provide incentives and realistic solutions. No password policy has ever made me choose better passwords. But a single link to KeePass did convince me.

 

 

 

 

It's impossible to cover all absurd rules people come up with.

 

If you use symbols, they aren't permitted. If you don't use symbols, they're required. If you use long passwords, they're too long, If you use short passwords, they're too short. And then of course everybody has their favorite characters and pet theories about password strength.

 

It's just annoying. It's one of those stupid traditions which never seems to die.

 

Unless I'm being asked for my opinion, I'm just doing what the customer wants. That's kind of besides the point though, as I'm just learning some more about regular expressions in general. I thought I'd come here to PHP freaks because the site members are usually pretty responsive and knowledgeable. I'm guilty, so shoot me.

Share this post


Link to post
Share on other sites

If you just trying to see if there are at least 2 digits, then temporarily strip all the non-numeric characters and count what is left.

$example = '5teeth4';
function atLeast2Numbers($e) {
    return ( strlen( preg_replace("/[^0-9,.]/", "", $e) ) >= 2); // Has at least two digits.
}

var_dump( atLeast2Numbers('fail5');      //false
var_dump( atLeast2Numbers('pass5and6');  //true

Share this post


Link to post
Share on other sites

 I guess my next question would be if I'm not needing a capturing group, does it hurt performance or anything if it is capturing vs non-capturing?

 

 

regex engine ignores does not capture groups in zero-width assertions (e.g. your positive lookahead), so there is no performance difference between using (?:[pattern]) vs. ([pattern]) unless you want to count the unmeasurably small amount of time it takes to read (and ignore) a single colon char. 

Edited by .josh

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.