soycharliente Posted January 14, 2013 Share Posted January 14, 2013 (edited) I read about 15 other threads. None quite close enough. I'm trying to validate a password for containing at least one character from three classes: uppercase, lowercase, number. All other characters can be a variety of things (A-Za-z0-9!@#$%^&*._-). The whole thing should be 6-32 characters. I tried to do this myself, but I'm not up on this lookahead stuff. At least, I'm pretty sure I need to use lookaheads. I've been using this online tester for writing the expressions and testing them with sample inputs. I cannot get ANYTHING to validate. I would love to understand lookaheads and how to check for a character class within the input in addition to getting this to work. So if you're up for it, I'm game for a teaching moment here as well. My current iteration of trying to figure this out: /^((?=[A-Za-z0-9]+)(?=[A-Za-z0-9!@#\$%\^&\*\._-]*)){6,32}$/ Any ideas? Thanks. Edited January 14, 2013 by charlieholder Quote Link to comment https://forums.phpfreaks.com/topic/273119-yet-another-password-regex/ Share on other sites More sharing options...
Jessica Posted January 14, 2013 Share Posted January 14, 2013 I'm not great at regex, I just wanted to say don't put an upper limit on passwords. I use several that are way longer than 32. Quote Link to comment https://forums.phpfreaks.com/topic/273119-yet-another-password-regex/#findComment-1405483 Share on other sites More sharing options...
kicken Posted January 14, 2013 Share Posted January 14, 2013 I don't limit passwords at all aside from minimum length/complexity limits. Let a user enter whatever characters they want for however long they want to. Once you hash the password with your algorithm of choice it doesn't really matter what their original input was. As for the complexity rule you want (one upper, lower, and numeric) do three separate simple tests rather than trying to come up with a complex regex: $pass = 'This is my pa55w0rd!'; $valid = preg_match('/[A-Z]/', $pass) && preg_match('/[a-z]/', $pass) && preg_match('/[0-9]/', $pass) Quote Link to comment https://forums.phpfreaks.com/topic/273119-yet-another-password-regex/#findComment-1405484 Share on other sites More sharing options...
Christian F. Posted January 14, 2013 Share Posted January 14, 2013 (edited) Here's a simple RegExp for setting a minimum password complexity of 8 characters, with at least one digit, one lower case letter and one upper case letter: $RegExp = '/^(?=.{8,})(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).*\\z/'; To explain what it does: ^ # Bind the RegExp to the beginning of the string. (?=.{8,}) # Followed by 8 or more characters (min length) (?=.*\\d) # At least one digit. (?=.*[a-z]) # At least one lower-case character. (?=.*[A-Z]) # At least one upper-case character. .*\\z # Followed by any number of characters, before the end of the string. Now, you might be wondering about the .* inside the lookaheads. Having it there allows the conditions to occur anywhere in the string, by allowing any number of characters in front, and not just for the first character. Edited January 14, 2013 by Christian F. Quote Link to comment https://forums.phpfreaks.com/topic/273119-yet-another-password-regex/#findComment-1405494 Share on other sites More sharing options...
Psycho Posted January 14, 2013 Share Posted January 14, 2013 That regex can be simplified. Since the lookaheads do not consume any characters, there is no need to put a lookahead at the beginning looking for 8 characters - simply do a length check at the end $RegExp = '/(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).{8,}/'; However, in addition to checking for at least one of each character class that regex will allow any characters. If you want to restrict which characters are allowed as you may have been insinuating - then you will need to modify that length check to include all the required characters as well as put the begin/end bindings to ensure there are no errant characters. $RegExp = '/^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[a-zA-Z\\d!@#$%^&*._-]{8,}$/'; ^ # Bind the RegExp to the beginning of the string. (?=.*[a-z]) # Anything, followed by at least one lowercase (non consuming) (?=.*[A-Z]) # Anything, followed by at least one uppercase (non consuming) (?=.*\\d) # Anything, followed by at least one number (non consuming) [a-zA-Z\\d!@#$%^&*._-]{8,} # All characters must be within this class and be 8+ in length $ # Bind the RegExp to the end of the string. Quote Link to comment https://forums.phpfreaks.com/topic/273119-yet-another-password-regex/#findComment-1405516 Share on other sites More sharing options...
Christian F. Posted January 14, 2013 Share Posted January 14, 2013 Good point on the length limit, Psycho. Thanks. Though, like Kicken I don't agree with limiting the entropy (or the max length) of a password. All you do is make it simpler for any attackers to crack it. A lot simpler. When it's hashed it'll be treated as binary data anyway, so it doesn't even matter if the characters are printable or not[1]. That's why my RegExp allows any character. [1] Well... Except for the fact that you've got to type those characters into the form, somehow. Quote Link to comment https://forums.phpfreaks.com/topic/273119-yet-another-password-regex/#findComment-1405518 Share on other sites More sharing options...
Psycho Posted January 14, 2013 Share Posted January 14, 2013 In theory, I agree that you should not restrict what characters can be entered. But, in practice, there are legitimate reasons for doing so. If a user is normally on a PC with a keyboard setup that allows some "non-traditional" characters, that user may have problems logging when away from that computer - i.e. on the road. Similarly, and probably more importantly, many characters that can easily be entered on a PC are either difficult or impossible to enter from a mobile device. Quote Link to comment https://forums.phpfreaks.com/topic/273119-yet-another-password-regex/#findComment-1405524 Share on other sites More sharing options...
soycharliente Posted January 14, 2013 Author Share Posted January 14, 2013 For some reason my "Topics & Posts" notification settings were set to none and my timezone was +1 GMT when I woke up this morning. Very strange. I missed all the discussion last night. I was up too because I couldn't sleep ;( Thank you for the line-by-line explanations of example code. I think I have a much better grasp on lookaheads now. Thanks for the comments about character classes and length too. I'm going to work on this based on the example code and comments and see what comes out. I'll post back here sometime after work today. Quote Link to comment https://forums.phpfreaks.com/topic/273119-yet-another-password-regex/#findComment-1405572 Share on other sites More sharing options...
soycharliente Posted January 15, 2013 Author Share Posted January 15, 2013 (edited) I'm not great at regex, I just wanted to say don't put an upper limit on passwords. I use several that are way longer than 32. Yeah. I guess it really doesn't matter to me how long it is. As long as the hash is the same in the end. Point taken. Let a user enter whatever characters they want for however long they want to. Once you hash the password with your algorithm of choice it doesn't really matter what their original input was. Makes sense. Why should I care what other characters they enter as long as I force them to use a few different character classes to make the password somewhat stronger. (?=.*\\d) # At least one digit. What's the difference between (?=.*\\d) and (?=.*[0-9]) in the regex? But, in practice, there are legitimate reasons for doing so. Oooh! Very interesting! I've never thought about that before. That being said, if you know that your password characters aren't available on mobile phone or other devices, then... maybe you shouldn't use them? lol So I've taken all your comments under advisement and decided to end with this: ^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9]).{6,64}$ What do you think? Edited January 15, 2013 by charlieholder Quote Link to comment https://forums.phpfreaks.com/topic/273119-yet-another-password-regex/#findComment-1405755 Share on other sites More sharing options...
Psycho Posted January 15, 2013 Share Posted January 15, 2013 What's the difference between (?=.*\\d) and (?=.*[0-9]) in the regex? Nothing. The \d is the character class for digits Oooh! Very interesting! I've never thought about that before. That being said, if you know that your password characters aren't available on mobile phone or other devices, then... maybe you shouldn't use them? lol Perhaps, but someone would only find that out after they already created their password on a PC and then later needed to log in on a mobile device. I'm not saying you should exclude characters only that there are some legitimate reasons for doing so. Quote Link to comment https://forums.phpfreaks.com/topic/273119-yet-another-password-regex/#findComment-1405769 Share on other sites More sharing options...
soycharliente Posted January 15, 2013 Author Share Posted January 15, 2013 Nothing. The \d is the character class for digits. Well, I knew that - lol. I guess I was just wondering if one was "better" than the other. Sounds like no. Quote Link to comment https://forums.phpfreaks.com/topic/273119-yet-another-password-regex/#findComment-1405770 Share on other sites More sharing options...
Jessica Posted January 15, 2013 Share Posted January 15, 2013 I'm going to add emoji to my passwords so I can ONLY login on my iPhone. That'll show me! Quote Link to comment https://forums.phpfreaks.com/topic/273119-yet-another-password-regex/#findComment-1405771 Share on other sites More sharing options...
soycharliente Posted January 15, 2013 Author Share Posted January 15, 2013 I'm going to add emoji to my passwords so I can ONLY login on my iPhone. That'll show me! 7000th post. It was a good one. I'll send you the URL when I'm done. You let me know how it goes Quote Link to comment https://forums.phpfreaks.com/topic/273119-yet-another-password-regex/#findComment-1405772 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.