views:

287

answers:

7
^([a-zA-Z0-9!@#$%^&*|()_\-+=\[\]{}:;\"',<.>?\/~`]{4,})$

Would this regular expression work for these rules?

  • Must be atleast 4 characters
  • Characters can be a mix of alphabet (capitalized/non-capitalized), numeric, and the following characters: ! @ # $ % ^ & * ( ) _ - + = | [ { } ] ; : ' " , < . > ? /

It's intended to be a password validator. The language is PHP.

+1  A: 

Regex buddy is your friend.

Andrew
No it's not....
Chris Lutz
Why not ......?
Ankur
It's not very useful. I know how to write regular expressions, and I can write my own, and if it's too complicated for me to write, I should be asking why I have to do the job in one regex. Why would I pay money for a tool that can only do half of that?
Chris Lutz
@Chris Lutz: Thanks. I thought I was alone with that attitude.
Tomalak
@Chris Lutz: My sole use for Regex Buddy is as a way of testing a regex over a range of parsing engines. In that role, regex buddy is very, very useful.
Andrew
@Andrew - Ah, I didn't know it could test regexes, too.
Chris Lutz
+1  A: 

You forgot the comma (,) and full stop (.) and added the tilde (~) and grave accent (`) that were not part of your specification. Additionally just a few characters inside a character set declaration have to be escaped:

^([a-zA-Z0-9!@#$%^&*()|_\-+=[\]{}:;"',<.>?/~`]{4,})$

And that as a PHP string declaration for preg_match:

'/^([a-zA-Z0-9!@#$%^&*()|_\\-+=[\\]{}:;"\',<.>?\\/~`]{4,})$/'
Gumbo
I've edited the original quoted regex to reflect , and . , and I've added ~ and ` to the specifications.
Nikko
A: 

I noticed that you essentially have all of ASCII, except for backslash, space and the control characters at the start, so what about this one, instead?

^([!-\[\]-~]{4,})$
Joey
Basically what I'm creating here is a password regular expression, and I need is a regex which isn't to strict (doesn't require you to have one capitalized, one special character, one number etc etc), but still has a white-list of "good" characters. Would your regex be able to do that?
Nikko
Btw, in addition to the data above, I'm using the regex with preg_match in PHP.
Nikko
Why are you forbidding some characters? And why on earth are you allowing 4 chars passwords??
Vinko Vrsalovic
Nikko: This regex is functionally equivalent to yours, it includes every ASCII character except < 32, space and backslash. So is is the same in regard to your expectations in your question. Whether white-listing password characters is a good idea or not isn't a question you should ask people like me who like even Unicode in their passwords :)
Joey
A: 

You are extra escaping and aren't using some predefined character classes (such as \w, or at least \d).

Besides of that and that you are anchoring at the beginning and at the end, meaning that the regex will only match if the string starts and ends matching, it looks correct:

^([a-zA-Z\d\-!$@#$%^&*()|_+=\[\]{};,."'<>?/~`]{4,})$

If you really mean to use this as a password validator, it reeks of insecurity:

  • Why are you allowing 4 chars passwords?
  • Why are you forbidding some characters? PHP can't handle some? Why would you care? Let the user enter the characters he pleases, after all you'll just end up storing a hash + salt of it.
Vinko Vrsalovic
The \w character class will match way more than just ASCII.
Joey
True, that's why I didn't use it.
Vinko Vrsalovic
@Johannes - Only in Perl. In PCRE I don't think it will.
Chris Lutz
`_-+` is an invalid range.
Gumbo
But OP isn't mentioning platform
Vinko Vrsalovic
In a comment they mentioned PHP.
Chris Lutz
Yes, I've edited the question accordingly.
Vinko Vrsalovic
@Vinko Vrsalovic: I don’t know any implementations that doesn’t throw an error on invalid character ranges.
Gumbo
Why are you allowing 4 chars passwords? - During development, I often use short passwords to make it easier to test logging into the system. In the final version, this will probably be changed to atleast 6 or 8 characters minimum.--Why are you forbidding some characters? ...hash + salt of it. - You are correct in saying that this would end up being hashed. But it was specified in my project description to not allow these characters when creating a password, so I'm just following it.
Nikko
* What I meant was it was specified in my project description to only allow this list of characters when creating a password
Nikko
Chris: And learned something again, thanks. But as I wrote that comment I didn't even know it was PHP.
Joey
@Johannes - It's cool. I love learning things, but I hate learning that PCRE doesn't work the same as Perl regexes. It bugs the hell out of me every time it comes up.
Chris Lutz
@Gumbo: Who said anything about that?
Vinko Vrsalovic
A: 

Impressive. Should work. Jeez..

Guru
+5  A: 

Yes?

Honestly, what are you asking for? Why don't you test it?

If, however, you want suggestions on improving it, some questions:

  1. What is this regex checking for?
  2. Why do you have such a large set of allowed characters?
  3. Why don't you use /\w/ instead of /0-9a-zA-Z_/?
  4. Why do you have the whole thing in ()s? You don't need to capture the whole thing, since you already have the whole thing, and they aren't needed to group anything.

What I would do is check the length separately, and then check against a regex to see if it has any bad characters. Your list of good characters seems to be sufficiently large that it might just be easier to do it that way. But it may depend on what you're doing it for.

EDIT: Now that I know this is PHP-centric, /\w/ is safe because PHP uses the PCRE library, which is not exactly Perl, and in PCRE, \w will not match Unicode word characters. Thus, why not check for length and ensure there are no invalid characters:

if(strlen($string) >= 4 && preg_match('[\s~\\]', $string) == 0) {
  # valid password
}

Alternatively, use the little-used POSIX character class [[:graph:]]. It should work pretty much the same in PHP as it does in Perl. [[:graph:]] matches any alphanumeric or punctuation character, which sounds like what you want, and [[:^graph:]] should match the opposite. To test if all characters match graph:

preg('^[[:graph:]]+$', $string) == 1

To test if any characters don't match graph:

preg('[[:^graph:]]', $string) == 0
Chris Lutz
I've tested the regex, but I just wanted to make sure that it's correct, as I'm not really good at making regular expressions (as you can see, the regex I've made isn't very optimized). Basically what I'm creating here is a password regular expression, and I need is a regex which isn't to strict (doesn't require you to have one capitalized, one special character, one number etc etc), but still has a white-list of "good" characters.Can you provide a better version of my regex?
Nikko
Thank you, this seems to be working.
Nikko
Can you explain though what '[\s~\\]' exactly checks against?
Nikko
'\s' matches whitespace (spaces and tabs), '\\' matches a backslash (you have to escape the backslash with another backslash), and '~' is just the tilde.
Chris Lutz
A: 

No. That regular expression would not work for the rules you state, for the simple reason that $ by default matches before the final character if it is a newline. You are allowing password strings like "1234\n".

The solution is simple. Either use \z instead of $, or apply the D modifier to the regex.

Geert