tags:

views:

184

answers:

4

I want to require the following:

  • Is greater than seven characters.
  • Contains at least two digits.
  • Contains at least two special (non-alphanumeric) characters.

...and I came up with this to do it:

(?=.{6,})(?=(.*\d){2,})(?=(.*\W){2,})

Now, I'd also like to make sure that no two sequential characters are the same. I'm having a heck of a time getting that to work though. Here's what I got that works by itself:

(\S)\1+

...but if I try to combine the two together, it fails.


I'm operating within the constraints of the application. It's default requirement is 1 character length, no regex, and no nonstandard characters.

Anyway...

Using this test harness, I would expect y90e5$ to match but y90e5$$ to not.

What an i missing?

+10  A: 

This is a bad place for a regex. You're better off using simple validation.

Tordek
Better yet: don't do the validation at all. Enforce a minimum length and **nothing else**. Restricting the domain of passwords by imposing constraints on them **makes them easier to crack**, not more secure.
Welbog
About the best thing you can hope to do is force people to change their passwords often, and even that is almost enough of a dealbreaker for me to not use a system (unless forced).
Carl Norum
Or, save the trouble of having "security questions" for when the user forgets his password by using the security question instead of the password prompt. i.e. require the user's password to be his favorite color. That's what all the professional sites are doing for security questions these days, so it must be very secure!</rant>
Jay
@Jay, though I agree "in principle", good sites ask the security question, then send a mail, then ask a "real data" question (bank account, or something else hidden for others). Then they send a new email to *reset* the password. Though drifting a bit OT, this is what Paypal uses (and they enforce certain characters and a certain length)
Abel
+5  A: 

Sometimes we cannot influence specifications and have to write the implementation regardless, i.e., when some ancient backoffice system has to be interfaced through the web but has certain restrictions on input, or just because your boss is asking you to.

EDIT: removed the regex that was based on the original regex of the asker.

altered original code to fit your description, as it didn't seem to really work:
EDIT: the q. was then updated to reflect another version. There are differences which I explain below:

My version: the two or more \W and \d can be repeated by each other, but cannot appear next to each other (this was my incorrect assumption), i fixed it for length>7 which is slightly more efficient to place as a typical "grab all" expression.

 ^(?!.*((\S)\1|\s))(?=.*(\d.+){2,})(?=.*(\W.+){2,}).{8,}

New version in original question: the two or more \W and the \d are allowed to appear next to each other. This version currently support length>=6, not length>7 as is explained in the text.

The current answer, corrected, should be something like this, which takes the updated q., my comments on length>7 and optimizations, then it looks like: ^(?!.*((\S)\1|\s))(?=(.*\d){2,})(?=(.*\W){2,}).{8,}.

Update: your original code doesn't seem to work, so I changed it a bit
Update: updated answer to reflect changes in question, spaces not allowed anymore

Abel
-1: A developer worth his salt isn't going to implement a "feature" he knows to be worse than not having it at all. +1: This is the correct answer to the OP's problem. Overall: +0.
Welbog
I've had to create interfaces to systems that were designed in the 60's that had severe limits on character input. I also know of a university that has internally certain restrictions on passwords. And it is not uncommon that "english words" are filtered out to force "good" passwords. Terrible, yes. But unfortunately, by many people considered "good" practice. Oh, and the worst: I recently registered with several hosting providers. My sensitive data is protected behind a **max 8-char length letters/digits only** password. In this world! I canceled.
Abel
@Abel: Good job cancelling the 8-character password account. Did you also call up the company in question to tell them why you cancelled? You get a +1 from me for proving you know the difference between right and wrong with respect to password domains.
Welbog
Haha, thanks for that. You got a +1 from me for focusing on that issue :). Yes, I told them. They were not convinced. So I asked them how I could trust the more severe parts of their backoffices and the handling of my CC and other details if the front was already wide open. They answered that it was all stored according to *"international data protection laws"*. Yeah, right. Behind 3-bit encryption, I'm sure. Oh, and in case you wondered: I had similar situations with 7 out of 10 hosting providers I tested (!!!). Scary.
Abel
RE 'A developer worth his salt isn't going to implement a "feature" he knows to be worse than not having it at all.' Really? A client says, "We want these features" and you're going to tell him no? You'd lose a contract over a disagreement about good password policy? Or if it's your boss dictating the policy, you'd be willing to lose your job over something like this? +1 for having the courage to stand on principle; -1e6 for lack of perspective.
Jay
@Jay: It's a developer's job to *solve* problems, not create more. I'd do what I can to convince a customer to not be an idiot. If the system I'd be writing for them needs security (e.g., a financial app), then that would be a dealbreaker for me. If the app is something pointless (e.g., a minor internal app) then I won't press the issue unnecessarily. The principle shouldn't be broken, but I know when the grief isn't worth the payoff.
Welbog
@Welbog: Well, I don't want to get into a protracted argument over a tangent, but it seems to me that the seller's job is to give the customer what he wants, even if that's not what you think is best. If I go to a restaurant and order a steak, it is not the waiter's job to refuse to serve it on the grounds that I am overweight and a salad would be healthier for me. Yes, the customer is paying for my expertise and I will tell him when I think he is making a mistake. But if he rejects my advice, that's his perogative. He's the one paying the bill.
Jay
A: 

If the rule was that passwords had to be two digits followed by three letters or some such, or course a regular expression would work very nicely. But I don't think regexes are really designed for the sort of rule you actually have. Even if you get it to work, it would be pretty cryptic to the poor sucker who has to maintain it later -- possibly you. I think it would be a lot simpler to just write a quick function that loops through the characters and counts how many total and how many of each type. Then at the end check the counts.

Just because you know how to use regexes doesn't mean you have to use them for everything. I have a cool cordless drill but I don't use it to put in nails.

Jay
Recent regular expression features with look around make this kind of questions relatively easy to solve. Of course, it is always debatable whether or not a regex is more readable or understandable then plain old imperative code.
Abel
+1  A: 

This may not be the most efficient but appears to work.

^(?!.*(\S)\1)(?=.{6,})(?=(.*\d){2,})(?=(.*\W){2,})

Test strings:

  • ad2f#we1$ //match valid.
  • adfwwe12#$ //No Match repeated ww.
  • y90e5$$ //No Match repeated $$.
  • y90e5$ //No Match too Short and only 1 \W class value.

One of the comments pointed out that the above regex allows spaces which are typically not used for password fields. While this doesn't appear to be a requirement of the original post, as pointed out a simple change will disallow spaces as well.

^(?!.*(\S)\1|.*\s)(?=.{6,})(?=(.*\d){2,})(?=(.*\W){2,})

Your regex engine may parse (?!.*(\S)\1|.*\s) differently. Just be aware and adjust accordingly.

All previous test results the same.
Test string with whitespace:

  • ad2f #we1$ //No match space in string.
Firestrand
If you copy my solutions, copy them correctly. The `+` in `\1+` is redundant.
Abel
Abel