114

I'm creating a regexp for password validation to be used in a Java application as a configuration parameter.

The regexp is:

^.*(?=.{8,})(?=..*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=]).*$

The password policy is:

  • At least 8 chars

  • Contains at least one digit

  • Contains at least one lower alpha char and one upper alpha char

  • Contains at least one char within a set of special chars (@#%$^ etc.)

  • Does not contain space, tab, etc.

I’m missing just point 5. I'm not able to have the regexp check for space, tab, carriage return, etc.

Could anyone help me?

Caleb Hattingh
  • 8,388
  • 2
  • 27
  • 42
Kerby82
  • 4,356
  • 12
  • 41
  • 65
  • 3
    Password rules are bad. Please see [Reference - Password Validation](https://stackoverflow.com/questions/48345922/reference-password-validation) for more info. – ctwheels Jan 29 '18 at 17:18

17 Answers17

332

Try this:

^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\S+$).{8,}$

Explanation:

^                 # start-of-string
(?=.*[0-9])       # a digit must occur at least once
(?=.*[a-z])       # a lower case letter must occur at least once
(?=.*[A-Z])       # an upper case letter must occur at least once
(?=.*[@#$%^&+=])  # a special character must occur at least once
(?=\S+$)          # no whitespace allowed in the entire string
.{8,}             # anything, at least eight places though
$                 # end-of-string

It's easy to add, modify or remove individual rules, since every rule is an independent "module".

The (?=.*[xyz]) construct eats the entire string (.*) and backtracks to the first occurrence where [xyz] can match. It succeeds if [xyz] is found, it fails otherwise.

The alternative would be using a reluctant qualifier: (?=.*?[xyz]). For a password check, this will hardly make any difference, for much longer strings it could be the more efficient variant.

The most efficient variant (but hardest to read and maintain, therefore the most error-prone) would be (?=[^xyz]*[xyz]), of course. For a regex of this length and for this purpose, I would dis-recommend doing it that way, as it has no real benefits.

Tomalak
  • 306,836
  • 62
  • 485
  • 598
  • 15
    @Kerby82: In Java strings, backslashes must be escaped. Try to use `\\s`. That's a Java requirement, not a regex requirement. – Tomalak Sep 27 '10 at 08:55
  • yes \t is pointless since \s include A whitespace character: [ \t\n\x0B\f\r]. But backslashing the \s now in java works perfectly. Thanks a lot! – Kerby82 Sep 27 '10 at 09:17
  • You can switch off multi-line mode explicitly as part of the regex if you need to by using (?-m: ... ) around everything else – Adrian Pronk Sep 27 '10 at 09:26
  • Is there a way to make one of these optional? Like I want at least alphanumeric, but special and upper chars are allowed. – Allov Nov 15 '10 at 14:47
  • 1
    @Allov Just think about it that way: Everything that is not enforced is optional. Just remove the checks for things you don't want to enforce. Should be easy to adapt the solution to your needs. – Tomalak Nov 16 '10 at 10:12
  • 4
    This answer has been added to the [Stack Overflow Regular Expression FAQ](http://stackoverflow.com/a/22944075/2736496), under "Common Validation Tasks". – aliteralmind Apr 10 '14 at 01:19
  • I think using `(?!.*\s)` instead of `(?=\S+$)` can make more sense ;). – shA.t Jul 29 '15 at 11:18
  • 1
    @shA.t It's the same thing. I only tried to keep the `(?=...)` pattern so it matches the setup of the rest of the expression.. – Tomalak Jul 29 '15 at 11:22
  • I suggest it just as OP says *Does not contain space, tab, etc.* BTW thanks at all ;). – shA.t Jul 29 '15 at 11:32
  • 2
    @shA.t Whether you say "contains only non-space characters" (`(?=\S+$)`) or "does not contain space characters" (`(?!.*\s)`) is a matter of preference. Use whatever you like better. :) – Tomalak Jul 29 '15 at 11:48
  • This allows on more special characters than just the ones listed. Why is that? I tried with the string `}[]{@123aaaBBB` and it worked just fine – Rakim Oct 12 '15 at 23:06
  • 1
    I noticed that the given expression allows also passwords that contain characters like ~ and | . I thought the expression allows following characters: @#$%^&+= – Stephan May 19 '17 at 07:37
  • 1
    @Stephan The expression allows all characters. It just makes a few of them *required*. – Tomalak May 19 '17 at 09:04
  • Yeah that's what i noticed. I thought it was restricted to those chars only. Thank you. – Stephan May 22 '17 at 05:33
  • If you find yourself building a password validator that *restricts* password length or usable character set in any way, you are already doing something wrong. This is never technically necessary and it's very user-unfriendly. (Whether a password validator that *requires* certain characters is a good idea is also being debated.) – Tomalak May 22 '17 at 06:46
  • You saved my life bro. Thanks. – viper Dec 08 '17 at 08:43
  • We are facing problem when we use these `#%&+` chars in the url while validating, looks these are reserved chars for http urls. Then how to avoid user not to use these chars ...? – Kanagavelu Sugumar Mar 27 '18 at 16:52
  • 1
    @KanagaveluSugumar You do not avoid those characters, you allow them and then encode them properly before putting them into the URL. Look up how url-encoding works in your programming language. – Tomalak Mar 27 '18 at 17:33
  • Also check out https://www.owasp.org/index.php/Password_special_characters if you want to use the standard special characters. – Javatar Jul 09 '19 at 08:17
58

simple example using regex

public class passwordvalidation {
    public static void main(String[] args) {
      String passwd = "aaZZa44@"; 
      String pattern = "(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\\S+$).{8,}";
      System.out.println(passwd.matches(pattern));
   }
}

Explanations:

  • (?=.*[0-9]) a digit must occur at least once
  • (?=.*[a-z]) a lower case letter must occur at least once
  • (?=.*[A-Z]) an upper case letter must occur at least once
  • (?=.*[@#$%^&+=]) a special character must occur at least once
  • (?=\\S+$) no whitespace allowed in the entire string
  • .{8,} at least 8 characters
agilob
  • 5,517
  • 2
  • 31
  • 43
agiles
  • 1,631
  • 3
  • 16
  • 18
  • 5
    .{5,10} represents minimum of 5 characters and maximum of 10 characters. Just in case anybody is looking for specific explanation. – abhy Apr 08 '15 at 09:11
  • @iabhi, I was looking for this. Thank you. – Akshatha Srinivas Feb 23 '18 at 09:26
  • I am trying to implement Regex on a password stored in a char array instead of a String because of security. But how does one apply regex to a char array? – AgentM Oct 08 '18 at 22:23
  • This accepts also (normally) non-allowed chars like "€" or "§" (i.e.: "1q@W€°§ß"). You should replace the last ".{8,}" with a list of allowed chars, e.g. "[@#$%^&+=a-zA-Z0-9]{8,}" – Sampisa Mar 08 '21 at 17:22
13

All the previously given answers use the same (correct) technique to use a separate lookahead for each requirement. But they contain a couple of inefficiencies and a potentially massive bug, depending on the back end that will actually use the password.

I'll start with the regex from the accepted answer:

^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\S+$).{8,}$

First of all, since Java supports \A and \z I prefer to use those to make sure the entire string is validated, independently of Pattern.MULTILINE. This doesn't affect performance, but avoids mistakes when regexes are recycled.

\A(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\S+$).{8,}\z

Checking that the password does not contain whitespace and checking its minimum length can be done in a single pass by using the all at once by putting variable quantifier {8,} on the shorthand \S that limits the allowed characters:

\A(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])\S{8,}\z

If the provided password does contain a space, all the checks will be done, only to have the final check fail on the space. This can be avoided by replacing all the dots with \S:

\A(?=\S*[0-9])(?=\S*[a-z])(?=\S*[A-Z])(?=\S*[@#$%^&+=])\S{8,}\z

The dot should only be used if you really want to allow any character. Otherwise, use a (negated) character class to limit your regex to only those characters that are really permitted. Though it makes little difference in this case, not using the dot when something else is more appropriate is a very good habit. I see far too many cases of catastrophic backtracking because the developer was too lazy to use something more appropriate than the dot.

Since there's a good chance the initial tests will find an appropriate character in the first half of the password, a lazy quantifier can be more efficient:

\A(?=\S*?[0-9])(?=\S*?[a-z])(?=\S*?[A-Z])(?=\S*?[@#$%^&+=])\S{8,}\z

But now for the really important issue: none of the answers mentions the fact that the original question seems to be written by somebody who thinks in ASCII. But in Java strings are Unicode. Are non-ASCII characters allowed in passwords? If they are, are only ASCII spaces disallowed, or should all Unicode whitespace be excluded.

By default \s matches only ASCII whitespace, so its inverse \S matches all Unicode characters (whitespace or not) and all non-whitespace ASCII characters. If Unicode characters are allowed but Unicode spaces are not, the UNICODE_CHARACTER_CLASS flag can be specified to make \S exclude Unicode whitespace. If Unicode characters are not allowed, then [\x21-\x7E] can be used instead of \S to match all ASCII characters that are not a space or a control character.

Which brings us to the next potential issue: do we want to allow control characters? The first step in writing a proper regex is to exactly specify what you want to match and what you don't. The only 100% technically correct answer is that the password specification in the question is ambiguous because it does not state whether certain ranges of characters like control characters or non-ASCII characters are permitted or not.

Jan Goyvaerts
  • 19,905
  • 7
  • 57
  • 67
9

You should not use overly complex Regex (if you can avoid them) because they are

  • hard to read (at least for everyone but yourself)
  • hard to extend
  • hard to debug

Although there might be a small performance overhead in using many small regular expressions, the points above outweight it easily.

I would implement like this:

bool matchesPolicy(pwd) {
    if (pwd.length < 8) return false;
    if (not pwd =~ /[0-9]/) return false;
    if (not pwd =~ /[a-z]/) return false;
    if (not pwd =~ /[A-Z]/) return false;
    if (not pwd =~ /[%@$^]/) return false;
    if (pwd =~ /\s/) return false;
    return true;
}
Martin Rauscher
  • 1,215
  • 1
  • 12
  • 15
  • And from a security perspective it is far better to force longer passwords, prevent well known passwords (like 12345 and pass=user) instead of making passwords super complicated and hard to remember. – Martin Rauscher Jan 07 '16 at 21:09
  • I like your approach above. Thank you for that! – Thomas Lang Dec 20 '18 at 07:21
2

Thanks for all answers, based on all them but extending sphecial characters:

@SuppressWarnings({"regexp", "RegExpUnexpectedAnchor", "RegExpRedundantEscape"})
String PASSWORD_SPECIAL_CHARS = "@#$%^`<>&+=\"!ºª·#~%&'¿¡€,:;*/+-.=_\\[\\]\\(\\)\\|\\_\\?\\\\";
int PASSWORD_MIN_SIZE = 8;
String PASSWORD_REGEXP = "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[" + PASSWORD_SPECIAL_CHARS + "])(?=\\S+$).{"+PASSWORD_MIN_SIZE+",}$";

Unit tested:

enter image description here

surfealokesea
  • 4,325
  • 4
  • 24
  • 34
1

Password Requirement :

  • Password should be at least eight (8) characters in length where the system can support it.
  • Passwords must include characters from at least two (2) of these groupings: alpha, numeric, and special characters.

    ^.*(?=.{8,})(?=.*\d)(?=.*[a-zA-Z])|(?=.{8,})(?=.*\d)(?=.*[!@#$%^&])|(?=.{8,})(?=.*[a-zA-Z])(?=.*[!@#$%^&]).*$
    

I tested it and it works

shA.t
  • 15,232
  • 5
  • 47
  • 95
Andrew
  • 11
  • 1
1

For anyone interested in minimum requirements for each type of character, I would suggest making the following extension over Tomalak's accepted answer:

^(?=(.*[0-9]){%d,})(?=(.*[a-z]){%d,})(?=(.*[A-Z]){%d,})(?=(.*[^0-9a-zA-Z]){%d,})(?=\S+$).{%d,}$

Notice that this is a formatting string and not the final regex pattern. Just substitute %d with the minimum required occurrences for: digits, lowercase, uppercase, non-digit/character, and entire password (respectively). Maximum occurrences are unlikely (unless you want a max of 0, effectively rejecting any such characters) but those could be easily added as well. Notice the extra grouping around each type so that the min/max constraints allow for non-consecutive matches. This worked wonders for a system where we could centrally configure how many of each type of character we required and then have the website as well as two different mobile platforms fetch that information in order to construct the regex pattern based on the above formatting string.

1

This one checks for every special character :

^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=\S+$).*[A-Za-z0-9].{8,}$
Rahul Agarwal
  • 3,743
  • 6
  • 24
  • 40
Ansu
  • 41
  • 8
1

Java Method ready for you, with parameters

Just copy and paste and set your desired parameters.

If you don't want a module, just comment it or add an "if" as done by me for special char

//______________________________________________________________________________
/**
 * Validation Password     */
//______________________________________________________________________________
private static boolean validation_Password(final String PASSWORD_Arg)    {
    boolean result = false;
    try {
        if (PASSWORD_Arg!=null) {
            //_________________________
            //Parameteres
            final String MIN_LENGHT="8";
            final String MAX_LENGHT="20";
            final boolean SPECIAL_CHAR_NEEDED=true;

            //_________________________
            //Modules
            final String ONE_DIGIT = "(?=.*[0-9])";  //(?=.*[0-9]) a digit must occur at least once
            final String LOWER_CASE = "(?=.*[a-z])";  //(?=.*[a-z]) a lower case letter must occur at least once
            final String UPPER_CASE = "(?=.*[A-Z])";  //(?=.*[A-Z]) an upper case letter must occur at least once
            final String NO_SPACE = "(?=\\S+$)";  //(?=\\S+$) no whitespace allowed in the entire string
            //final String MIN_CHAR = ".{" + MIN_LENGHT + ",}";  //.{8,} at least 8 characters
            final String MIN_MAX_CHAR = ".{" + MIN_LENGHT + "," + MAX_LENGHT + "}";  //.{5,10} represents minimum of 5 characters and maximum of 10 characters

            final String SPECIAL_CHAR;
            if (SPECIAL_CHAR_NEEDED==true) SPECIAL_CHAR= "(?=.*[@#$%^&+=])"; //(?=.*[@#$%^&+=]) a special character must occur at least once
            else SPECIAL_CHAR="";
            //_________________________
            //Pattern
            //String pattern = "(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\\S+$).{8,}";
            final String PATTERN = ONE_DIGIT + LOWER_CASE + UPPER_CASE + SPECIAL_CHAR + NO_SPACE + MIN_MAX_CHAR;
            //_________________________
            result = PASSWORD_Arg.matches(PATTERN);
            //_________________________
        }    

    } catch (Exception ex) {
        result=false;
    }

    return result;
}        
Fausto70
  • 457
  • 3
  • 17
1

Also You Can Do like This.

 public boolean isPasswordValid(String password) {


    String regExpn =
            "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\\S+$).{8,}$";

    CharSequence inputStr = password;

    Pattern pattern = Pattern.compile(regExpn,Pattern.CASE_INSENSITIVE);
    Matcher matcher = pattern.matcher(inputStr);

    if(matcher.matches())
        return true;
    else
        return false;
}
RANAJEET BARIK
  • 117
  • 1
  • 7
1

Use Passay library which is powerful api.

0

I think this can do it also (as a simpler mode):

^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])[^\s]{8,}$

[Regex Demo]

shA.t
  • 15,232
  • 5
  • 47
  • 95
0

easy one

("^ (?=.* [0-9]) (?=.* [a-z]) (?=.* [A-Z]) (?=.* [\\W_])[\\S]{8,10}$")

  1. (?= anything ) ->means positive looks forward in all input string and make sure for this condition is written .sample(?=.*[0-9])-> means ensure one digit number is written in the all string.if not written return false .

  2. (?! anything ) ->(vise versa) means negative looks forward if condition is written return false.

    close meaning ^(condition)(condition)(condition)(condition)[\S]{8,10}$

Community
  • 1
  • 1
ibrahem shabban
  • 751
  • 5
  • 5
  • Whilst code only answers may provide a solution to the problem, some explanation would greatly improve the quality of the answer. – Nigel Ren Dec 01 '17 at 16:23
0
String s=pwd;
int n=0;
for(int i=0;i<s.length();i++)
{
    if((Character.isDigit(s.charAt(i))))
    {
        n=5;
        break;
    }
    else
    {

    }
}
for(int i=0;i<s.length();i++)
{
    if((Character.isLetter(s.charAt(i))))
    {
        n+=5;
        break;
    }
    else
    {

    }

}

if(n==10)
{
    out.print("Password format correct <b>Accepted</b><br>");

}
else
{
    out.print("Password must be alphanumeric <b>Declined</b><br>");
}

Explanation:

  1. First set the password as a string and create integer set o.
  2. Then check the each and every char by for loop.
  3. If it finds number in the string then the n add 5. Then jump to the next for loop. Character.isDigit(s.charAt(i))
  4. This loop check any alphabets placed in the string. If its find then add one more 5 in n. Character.isLetter(s.charAt(i))
  5. Now check the integer n by the way of if condition. If n=10 is true given string is alphanumeric else its not.
0

Sample code block for strong password:

(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z0-9])(?=\\S+$).{6,18}
  1. at least 6 digits
  2. up to 18 digits
  3. one number
  4. one lowercase
  5. one uppercase
  6. can contain all special characters
0

RegEx is -

^(?:(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=]).*)[^\s]{8,}$
  1. at least 8 digits {8,}
  2. at least one number (?=.*\d)
  3. at least one lowercase (?=.*[a-z])
  4. at least one uppercase (?=.*[A-Z])
  5. at least one special character (?=.*[@#$%^&+=])
  6. No space [^\s]
Ankit Kumar Rajpoot
  • 3,495
  • 23
  • 22
0

A more general answer which accepts all the special characters including _ would be slightly different:

^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[\W|\_])(?=\S+$).{8,}$

The difference (?=.*[\W|\_]) translates to "at least one of all the special characters including the underscore".