Regexp Java para validação de senha

109

Estou criando um regexp para validação de senha para ser usado em um aplicativo Java como um parâmetro de configuração.

O regexp é:

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

A política de senha é:

  • Pelo menos 8 caracteres

  • Contém pelo menos um dígito

  • Contém pelo menos um caractere alfa inferior e um caractere alfa superior

  • Contém pelo menos um caractere em um conjunto de caracteres especiais ( @#%$^etc.)

  • Não contém espaço, tabulação, etc.

Estou perdendo apenas o ponto 5. Não consigo fazer com que a regexp verifique se há espaço, tab, retorno de carro, etc.

Alguém pode ajudar-me?

Kerby82
fonte
3
Regras de senha são ruins. Por favor, veja Referência - Validação de Senha para mais informações.
ctwheels de

Respostas:

317

Experimente isto:

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

Explicação:

^                 # 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

É fácil adicionar, modificar ou remover regras individuais, uma vez que cada regra é um "módulo" independente.

A (?=.*[xyz])construção devora toda a string ( .*) e retrocede até a primeira ocorrência onde [xyz]pode corresponder. É bem-sucedido se [xyz]for encontrado, mas falha caso contrário.

A alternativa seria utilizar um qualificador relutantes: (?=.*?[xyz]). Para uma verificação de senha, isso dificilmente fará qualquer diferença, para strings muito mais longas, poderia ser a variante mais eficiente.

A variante mais eficiente (mas mais difícil de ler e manter, portanto, a mais sujeita a erros) seria (?=[^xyz]*[xyz]), é claro. Para uma regex desse tamanho e para essa finalidade, eu não recomendaria fazer dessa forma, pois não tem benefícios reais.

Tomalak
fonte
15
@ Kerby82: Em strings Java, as barras invertidas devem ter escape. Tente usar \\s. Esse é um requisito do Java, não um requisito do regex.
Tomalak
1
@Allov Pense assim: tudo o que não é obrigatório é opcional. Apenas remova as verificações de coisas que você não deseja impor. Deve ser fácil adaptar a solução às suas necessidades.
Tomalak
3
Esta resposta foi adicionada às Perguntas frequentes sobre expressões regulares do Stack Overflow , em "Tarefas comuns de validação".
aliteralmind de
1
@ shA.t É a mesma coisa. Eu apenas tentei manter o (?=...)padrão para que ele correspondesse à configuração do resto da expressão.
Tomalak
2
@ shA.t Se você disser "contém apenas caracteres sem espaço" ( (?=\S+$)) ou "não contém caracteres de espaço" ( (?!.*\s)) é uma questão de preferência. Use o que você quiser melhor. :)
Tomalak
55

exemplo simples usando 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));
   }
}

Explicações:

  • (?=.*[0-9]) um dígito deve ocorrer pelo menos uma vez
  • (?=.*[a-z]) uma letra minúscula deve ocorrer pelo menos uma vez
  • (?=.*[A-Z]) uma letra maiúscula deve ocorrer pelo menos uma vez
  • (?=.*[@#$%^&+=]) um caractere especial deve ocorrer pelo menos uma vez
  • (?=\\S+$) nenhum espaço em branco permitido em toda a string
  • .{8,} pelo menos 8 caracteres
ágil
fonte
5
. {5,10} representa no mínimo 5 caracteres e no máximo 10 caracteres. Caso alguém esteja procurando uma explicação específica.
abhy de
@iabhi, eu estava procurando por isso. Obrigado.
Akshatha Srinivas
Estou tentando implementar Regex em uma senha armazenada em uma matriz char em vez de uma String por causa da segurança. Mas como aplicar regex a uma matriz char?
AgentM
13

Todas as respostas fornecidas anteriormente usam a mesma técnica (correta) para usar um lookahead separado para cada requisito. Mas eles contêm algumas ineficiências e um bug potencialmente enorme, dependendo do back-end que realmente usará a senha.

Vou começar com a regex da resposta aceita:

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

Em primeiro lugar, uma vez que o Java suporta \Ae \zeu prefiro usá-los para garantir que toda a string seja validada, independentemente de Pattern.MULTILINE. Isso não afeta o desempenho, mas evita erros quando os regexes são reciclados.

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

Verificar se a senha não contém espaços em branco e verificar seu comprimento mínimo pode ser feito em uma única passagem usando o all de uma vez, colocando o quantificador de variável {8,}na abreviação \Sque limita os caracteres permitidos:

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

Se a senha fornecida contiver um espaço, todas as verificações serão feitas, apenas para que a verificação final falhe no espaço. Isso pode ser evitado substituindo todos os pontos por \S:

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

O ponto só deve ser usado se você realmente quiser permitir qualquer caractere. Caso contrário, use uma classe de caracteres (negada) para limitar sua regex apenas aos caracteres que são realmente permitidos. Embora faça pouca diferença neste caso, não usar o ponto quando algo mais for mais apropriado é um hábito muito bom. Vejo muitos casos de retrocesso catastrófico porque o desenvolvedor estava com preguiça de usar algo mais apropriado do que o ponto.

Como há uma boa chance de os testes iniciais encontrarem um caractere apropriado na primeira metade da senha, um quantificador lento pode ser mais eficiente:

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

Mas agora a questão realmente importante: nenhuma das respostas menciona o fato de que a pergunta original parece ter sido escrita por alguém que pensa em ASCII. Mas em Java, as strings são Unicode. Os caracteres não ASCII são permitidos nas senhas? Em caso afirmativo, apenas espaços ASCII não são permitidos ou todos os espaços em branco Unicode devem ser excluídos.

Por padrão, \scorresponde apenas a espaços em branco ASCII, portanto, seu inverso \Scorresponde a todos os caracteres Unicode (espaços em branco ou não) e todos os caracteres ASCII que não sejam de espaços em branco. Se os caracteres Unicode forem permitidos, mas os espaços Unicode não, o UNICODE_CHARACTER_CLASSsinalizador pode ser especificado para \Sexcluir os espaços em branco Unicode. Se os caracteres Unicode não forem permitidos, eles [\x21-\x7E]podem ser usados ​​em vez de \Spara corresponder a todos os caracteres ASCII que não sejam um espaço ou um caractere de controle.

O que nos leva ao próximo problema potencial: queremos permitir personagens de controle? A primeira etapa para escrever uma regex adequada é especificar exatamente o que você deseja corresponder e o que não. A única resposta 100% tecnicamente correta é que a especificação da senha na pergunta é ambígua, porque não indica se determinados intervalos de caracteres, como caracteres de controle ou caracteres não ASCII, são permitidos ou não.

Jan Goyvaerts
fonte
9

Você não deve usar Regex excessivamente complexo (se puder evitá-los) porque eles são

  • difícil de ler (pelo menos para todos menos para você)
  • difícil de estender
  • difícil de depurar

Embora possa haver uma pequena sobrecarga de desempenho no uso de muitas pequenas expressões regulares, os pontos acima superam isso facilmente.

Eu implementaria assim:

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
fonte
E de uma perspectiva de segurança é muito melhor forçar senhas mais longas, evitar senhas conhecidas (como 12345 e pass = user) em vez de tornar as senhas muito complicadas e difíceis de lembrar.
Martin Rauscher
Eu gosto da sua abordagem acima. Obrigado por isso!
Thomas Lang
1

Requisito de senha:

  • A senha deve ter pelo menos oito (8) caracteres quando o sistema puder suportá-la.
  • As senhas devem incluir caracteres de pelo menos dois (2) desses agrupamentos: alfa, numérico e caracteres especiais.

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

Eu testei e funciona

Andrew
fonte
1

Para qualquer pessoa interessada nos requisitos mínimos para cada tipo de personagem, sugiro fazer a seguinte extensão sobre a resposta aceita de Tomalak:

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

Observe que esta é uma string de formatação e não o padrão regex final. Basta substituir% d com as ocorrências mínimas necessárias para: dígitos, minúsculas, maiúsculas, não dígitos / caracteres e senha inteira (respectivamente). Ocorrências máximas são improváveis ​​(a menos que você queira um máximo de 0, rejeitando efetivamente qualquer um desses caracteres), mas essas também podem ser facilmente adicionadas. Observe o agrupamento extra em torno de cada tipo, de modo que as restrições mín. / Máx. Permitam correspondências não consecutivas. Isso funcionou maravilhosamente bem para um sistema em que poderíamos configurar centralmente quantos de cada tipo de caractere exigíamos e, em seguida, fazer com que o site, bem como duas plataformas móveis diferentes buscassem essas informações, a fim de construir o padrão regex com base na string de formatação acima.

Demetrios Christopher
fonte
1

Este verifica todos os caracteres especiais:

^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=\S+$).*[A-Za-z0-9].{8,}$
Ansu
fonte
1

Método Java pronto para você, com parâmetros

Basta copiar e colar e definir os parâmetros desejados.

Se você não quiser um módulo, apenas comente-o ou adicione um "se" como feito por mim para caractere especial

//______________________________________________________________________________
/**
 * 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
fonte
1

Use a biblioteca Passay , que é uma API poderosa.

Balasubramanian Rengasamy
fonte
0

Acho que isso também pode fazer (como um modo mais simples):

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

[Demo Regex]

shA.t
fonte
0

Facil

("^ (? =. * [0-9]) (? =. * [Az]) (? =. * [AZ]) (? =. * [\\ W _]) [\\ S] {8 , 10} $ ")

  1. (? = qualquer coisa) -> significa que o positivo olha para a frente em todas as strings de entrada e certifique-se de que esta condição seja escrita .sample (? =. * [0-9]) -> significa que um número de dígito é escrito em todas as strings. E se não escrito, retorna falso .

  2. (?! qualquer coisa) -> (vice-versa) significa que negativo olha para a frente se a condição é escrita retorna falsa .

    fechar significado ^ (condição) (condição) (condição) (condição) [\ S] {8,10} $

ibrahem shabban
fonte
Embora as respostas apenas em código possam fornecer uma solução para o problema, alguma explicação melhoraria muito a qualidade da resposta.
Nigel Ren
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>");
}

Explicação:

  1. Primeiro defina a senha como uma string e crie o conjunto inteiro o.
  2. Em seguida, verifique cada caractere por loop.
  3. Se encontrar um número na string, n adiciona 5. Em seguida, pula para o próximo loop for. Character.isDigit (s.charAt (i))
  4. Este loop verifica todos os alfabetos colocados na string. Se for encontrado, então adicione mais 5 em n. Character.isLetter (s.charAt (i))
  5. Agora verifique o inteiro n através da condição if. Se n = 10 for verdadeiro, a string dada é alfanumérica, caso contrário, não.
Naresh Babu
fonte
0

Também você pode fazer assim.

 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
fonte
0

Bloco de código de amostra para senha forte:

(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z0-9])(?=\\S+$).{6,18}
  1. pelo menos 6 dígitos
  2. até 18 dígitos
  3. um número
  4. uma minúscula
  5. uma letra maiúscula
  6. pode conter todos os caracteres especiais
Sedrettin Çalışkan
fonte
0

RegEx é -

^(?:(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=]).*)[^\s]{8,}$
  1. pelo menos 8 dígitos {8,}
  2. pelo menos um número (? =. * \ d)
  3. pelo menos uma minúscula (? =. * [az])
  4. pelo menos uma maiúscula (? =. * [AZ])
  5. pelo menos um caractere especial (? =. * [@ # $% ^ & + =])
  6. Sem espaço [^ \ s]
Ankit Kumar Rajpoot
fonte