Expressão regular para verificar se a senha é “8 caracteres incluindo 1 letra maiúscula, 1 caractere especial, caracteres alfanuméricos”

102

Eu quero uma expressão regular para verificar isso

a senha deve ter oito caracteres, incluindo uma letra maiúscula, um caractere especial e caracteres alfanuméricos.

E aqui está minha expressão de validação que é para oito caracteres, incluindo uma letra maiúscula, uma letra minúscula e um número ou caractere especial.

(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$"

Como posso escrever para uma senha de oito caracteres, incluindo uma letra maiúscula, um caractere especial e caracteres alfanuméricos?

Rania Umair
fonte
26
Por que você precisa de uma expressão regular para isso? Uma expressão regular completa que corresponda aos seus requisitos será muito longa e complexa. É mais fácil escrever suas restrições em código C #.
Greg Hewgill
32
Você considerou verificar se há uma senha forte, em vez de verificar se a senha atende a algumas regras arbitrárias que são um proxy imperfeito para uma senha forte? Existem muitas bibliotecas e programas que, quando alimentados com uma senha, determinam sua força.
Wayne Conrad
4
@GregHewgill Eu votaria positivamente em seu comentário se pudesse :-) Isso parece outro caso de "se tudo o que você tem é um martelo, tudo começa a parecer um prego".
Christian.K
3
Você precisa de exatamente um caractere maiúsculo / especial ou pelo menos um?
mmdemirbas
4
Por requisito do usuário, você quer dizer que seu usuário está ditando os detalhes da implementação? Talvez eles devam codificar sozinhos, então. Para ser honesto, acho que seria mais fácil de manter e entender se você apenas criasse contadores e verificasse cada personagem um por um, incrementando os contadores apropriados para cada personagem que corresponde a uma regra. Do ponto de vista técnico, não é algo que irá impressionar ninguém, mas por que complicar as coisas com algo sujeito a erros e difícil de atualizar?

Respostas:

132

A expressão regular que você procura provavelmente será enorme e um pesadelo de se manter, especialmente para pessoas que não estão familiarizadas com expressões regulares.

Acho que seria mais fácil quebrar sua regex e fazer isso um pouco de cada vez. Pode demorar um pouco mais, mas tenho certeza de que mantê-lo e depurá-lo seria mais fácil. Isso também permitiria que você fornecesse mensagens de erro mais direcionadas aos seus usuários (além de apenas Invalid Password), o que deve melhorar a experiência do usuário.

Pelo que estou vendo, você é bastante fluente em regex, então presumo que fornecer as expressões regulares para fazer o que você precisa seria inútil.

Vendo seu comentário, é assim que eu faria:

  • Deve ter oito caracteres: você não precisa de uma regex para isso. Usar a .Lengthpropriedade deve ser suficiente.

  • Incluindo uma letra maiúscula: você pode usar a [A-Z]+expressão regular. Se a string contiver pelo menos uma letra maiúscula, essa expressão regular resultará true.

  • Um caractere especial: Você pode usar o \Wque corresponderá a qualquer caractere que não seja uma letra ou um número ou então, você pode usar algo assim [!@#]para especificar uma lista personalizada de caracteres especiais. Nota que embora personagens como $, ^, (e )são caracteres especiais na linguagem de expressão regular, então eles precisam ser escapado assim: \$. Resumindo, você pode usar o \W.

  • Caracteres alfanuméricos: o uso de \w+deve corresponder a qualquer letra, número e sublinhado.

Dê uma olhada neste tutorial para obter mais informações.

npinti
fonte
2
Eu não escrevi isso
sozinho
4
@RaniaUmair: Acho que seu comentário prova meu ponto. Eu recomendaria que você decompô-lo como eu especifiquei.
npinti
35
+1 Regex é poderoso, mas não foi feito para resolver nenhum problema no universo
Cristian Lupascu
@ w0lf: Eu não poderia concordar mais. Regex é poderoso, no entanto, ele se torna muito complexo muito rápido, então é melhor mantê-lo simples.
npinti
você pode me ajudar eu preciso de um regx que aceite pelo menos um número e no máximo 3 outros charecters podem ser qualquer coisa
Lijo
107
(                   # Start of group
    (?=.*\d)        #   must contain at least one digit
    (?=.*[A-Z])     #   must contain at least one uppercase character
    (?=.*\W)        #   must contain at least one special symbol
       .            #     match anything with previous condition checking
         {8,8}      #        length is exactly 8 characters
)                   # End of group

Em uma linha:

((?=.*\d)(?=.*[A-Z])(?=.*\W).{8,8})

Editar 28/05/2019:

Você precisa corresponder a toda a string de entrada. Portanto, você pode delimitar a regex entre ^e $para evitar assumir acidentalmente correspondências parciais como correspondendo à entrada inteira:

^((?=.*\d)(?=.*[A-Z])(?=.*\W).{8,8})$

Fontes:

mmdemirbas
fonte
58
Porque consiste em 12 caracteres
mmdemirbas
mais uma condição não deve começar com um dígito, como posso fazer isso?
Lijo
7
Você pode encurtá-lo usando {8} em vez de corresponder a 8 caracteres
Angelo Tricarico,
sua correspondência para $ 1eerrrrrrr .. não tem letras maiúsculas.
Shilpi Jaiswal
@ShilpiJaiswal Ou você está usando um sinalizador para correspondência sem distinção entre maiúsculas e minúsculas ou fazendo uma "localização" em vez de "correspondência". Para garantir que você está combinando toda a string de entrada, você pode colocar a regex entre ^e $. Tente isto:^((?=.*\d)(?=.*[A-Z])(?=.*\W).{8,8})$
mmdemirbas
35

Tantas respostas .... todas ruins!

Expressões regulares não têm um operador AND, então é muito difícil escrever uma regex que corresponda a senhas válidas, quando a validade é definida por algo E algo mais E algo mais ...

Mas, expressões regulares fazem têm um operador OR, por isso, basta aplicar o teorema de DeMorgan, e escrever um regex que corresponde inválidos senhas.

qualquer coisa com menos de 8 caracteres OU qualquer coisa sem números OU qualquer coisa sem maiúsculas OU qualquer coisa sem caracteres especiais

Assim:

^(.{0,7}|[^0-9]*|[^A-Z]*|[a-zA-Z0-9]*)$

Se alguma coisa corresponder a isso, é uma senha inválida .

Matt Timmermans
fonte
3
Se o OP quisesse exatamente 8 caracteres, você precisaria adicionar |.{9,}. +1 para o conceito
Daniel
Ótima e simples solução para a questão, embora eu concorde que uma única expressão regular não é a ideal para o problema real.
Siderite Zackwehdex
1
As expressões regulares não tem e operadores, eles são chamados de verificação à frente / lookbehind afirmações.
relativamente_random
13

A resposta é não usar uma expressão regular. Isso é jogos e contagem.

As expressões regulares são uma questão de ordem.

Em sua vida como programador, você terá que fazer muitas coisas que não fazem sentido. Aprenda a cavar um nível mais profundo. Aprenda quando a pergunta está errada.

A pergunta (se mencionou expressões regulares) está errada.

Pseudocódigo (tem alternado entre muitas linguagens, ultimamente):

if s.length < 8:
    return False
nUpper = nLower = nAlphanum = nSpecial = 0
for c in s:
    if isUpper(c):
        nUpper++
    if isLower(c):
        nLower++
    if isAlphanumeric(c):
        nAlphanum++
    if isSpecial(c):
        nSpecial++
return (0 < nUpper) and (0 < nAlphanum) and (0 < nSpecial)

Aposto que você leu e entendeu o código acima quase instantaneamente. Aposto que você demorou muito mais com a regex e tem menos certeza de que está correto. Estender a regex é arriscado. Estendeu o imediato acima, muito menos.

Observe também que a pergunta foi formulada de maneira imprecisa. O conjunto de caracteres é ASCII ou Unicode ou ?? Meu palpite, ao ler a pergunta, é que pelo menos um caractere minúsculo é assumido. Portanto, acho que a última regra assumida deve ser:

return (0 < nUpper) and (0 < nLower) and (0 < nAlphanum) and (0 < nSpecial)

(Mudar de chapéu para focado na segurança, esta é uma regra realmente irritante / inútil.)

Aprender a saber quando a pergunta está errada é muito mais importante do que respostas inteligentes. Uma resposta inteligente para a pergunta errada quase sempre está errada.

Preston L. Bannister
fonte
2
Concordo. Quanto mais pessoas você trabalha, mais código precisa ser legível, embora algumas implementações de regexp que eu vi como respostas sejam bastante claras
Nicola Peluchetti
Gosto que alguns usuários como você tenham coragem de dizer que Regex nem sempre é a melhor solução para aplicar e que às vezes a programação simples é mais legível.
schlebe
12

Como um exemplo de como isso poderia ser feito com um regex legível / sustentável.

Para uma regex mais longa, você sempre deve usar RegexOptions.IgnorePatternWhitespacepara permitir espaços em branco e comentários na expressão para melhor legibilidade.

String[] passwords = { "foobar", "Foobar", "Foobar1", "Fooobar12" };

foreach (String s in passwords) {

    Match password = Regex.Match(s, @"
                                      ^              # Match the start of the string
                                       (?=.*\p{Lu})  # Positive lookahead assertion, is true when there is an uppercase letter
                                       (?=.*\P{L})   # Positive lookahead assertion, is true when there is a non-letter
                                       \S{8,}        # At least 8 non whitespace characters
                                      $              # Match the end of the string
                                     ", RegexOptions.IgnorePatternWhitespace);

    if (password.Success) {
        Console.WriteLine(s + ": valid");
    }
    else {
        Console.WriteLine(s + ": invalid");
    }
}

Console.ReadLine();
estema
fonte
Esta é a melhor maneira de abusar do lookahead assertiontipo de um padrão "and" para cobrir toda a restrição em uma única regex. Funciona para mais restrições e pode ser facilmente gerado se algumas restrições forem habilitadas / desabilitadas pela configuração.
dognose
2
O uso de categorias Unicode é uma excelente ideia. O mundo é mais amplo do que ASCII!
Walter Tross
1

Se você precisar de apenas uma caixa alta e um caractere especial, isso deve funcionar:

@"^(?=.{8,}$)(?=[^A-Z]*[A-Z][^A-Z]*$)\w*\W\w*$"
user1096188
fonte
A string AAaaaaaaa#não está bem de acordo com esta expressão
Cristian Lupascu
3
Bem, tem 10, não 8 caracteres e contém mais de uma maiúscula, então deve falhar ...
user1096188
4
Você está certo, ele não dizer isso em questão. Achei que essas regras eram mais como "pelo menos uma maiúscula" em vez de "exatamente uma maiúscula" . Não tenho certeza se é isso que o OP queria.
Cristian Lupascu
1

A expressão regular que você estava procurando: /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#\$%\^&\*\[\]"\';:_\-<>\., =\+\/\\]).{8,}$/u.

Exemplo e teste: http://regexr.com/3fhr4

Lucas silva
fonte
Vagas são permitidas
Swimburger
1
@sniels Basta alterar o .antes do {8,}para [^\s].
Lucas Silva
0

Esta pergunta começa a ser viral e aparecem muitas sugestões interessantes.

Sim, escrever à mão é difícil. Portanto, uma solução mais fácil é usar um modelo. Embora o regex resultante possa não ser o ideal, será mais fácil manter e / ou alterar, e o usuário terá um melhor controle sobre o resultado. É possível que eu tenha perdido alguma coisa, então qualquer crítica construtiva será útil.

Estes links podem ser interessantes: corresponder a pelo menos 2 dígitos 2 letras em qualquer ordem em uma string , Linguagem de Expressão Regular , Grupos de captura

Estou usando este modelo com (?=(?:.*?({type})){({count})})base em todas as regex que vi no SO. A próxima etapa é substituir o padrão necessário ( number, special character...) e adicionar configuração para comprimento.

Eu fiz uma pequena classe para compor o regex PasswordRegexGenerator.cs Um exemplo:

string result = new PasswordRegexGenerator ( )
        .UpperCase ( 3, -1 )    // ... {3,}
        .Number ( 2, 4 )        // ... {2,4}
        .SpecialCharacter ( 2 ) // ... {2}
        .Total ( 8,-1 )
        .Compose ( );

/// <summary>
/// Generator for regular expression, validating password requirements.
/// </summary>
public class PasswordRegexGenerator
{
    private string _elementTemplate = "(?=(?:.*?({type})){({count})})";

    private Dictionary<string, string> _elements = new Dictionary<string, string> {
        { "uppercase", "[A-Z]" },
        { "lowercase", "[a-z]" },
        { "number", @"\d" },
        { "special", @"\W" },
        { "alphanumeric", @"\w" }
    };

    private StringBuilder _sb = new StringBuilder ( );

    private string Construct ( string what, int min, int max )
    {
        StringBuilder sb = new StringBuilder ( _elementTemplate );
        string count = min.ToString ( );

        if ( max == -1 )
        {
            count += ",";
        }
        else if ( max > 0 )
        {
            count += "," + max.ToString();
        }

        return sb
            .Replace ( "({type})", what )
            .Replace ( "({count})", count )
            .ToString ( );
    }

    /// <summary>
    /// Change the template for the generation of the regex parts
    /// </summary>
    /// <param name="newTemplate">the new template</param>
    /// <returns></returns>
    public PasswordRegexGenerator ChangeRegexTemplate ( string newTemplate )
    {
        _elementTemplate = newTemplate;
        return this;
       }

    /// <summary>
    /// Change or update the regex for a certain type ( number, uppercase ... )
    /// </summary>
    /// <param name="name">type of the regex</param>
    /// <param name="regex">new value for the regex</param>
    /// <returns></returns>
    public PasswordRegexGenerator ChangeRegexElements ( string name, string regex )
    {
        if ( _elements.ContainsKey ( name ) )
        {
            _elements[ name ] = regex;
        }
        else
        {
            _elements.Add ( name, regex );
        }
        return this;
    }

    #region construction methods 

    /// <summary>
    /// Adding number requirement
    /// </summary>
    /// <param name="min"></param>
    /// <param name="max"></param>
    /// <returns></returns>
    public PasswordRegexGenerator Number ( int min = 1, int max = 0 )
    {
        _sb.Append ( Construct ( _elements[ "number" ], min, max ) );
        return this;
    }

    public PasswordRegexGenerator UpperCase ( int min = 1, int max = 0 )
    {
        _sb.Append ( Construct ( _elements[ "uppercase" ], min, max ) );
        return this;
    }

    public PasswordRegexGenerator LowerCase ( int min = 1, int max = 0 )
    {
        _sb.Append ( Construct ( _elements[ "lowercase" ], min, max ) );
        return this;
    }

    public PasswordRegexGenerator SpecialCharacter ( int min = 1, int max = 0 )
    {
        _sb.Append ( Construct ( _elements[ "special" ], min, max ) );
        return this;
    }

    public PasswordRegexGenerator Total ( int min, int max = 0 )
    {
        string count = min.ToString ( ) + ( ( max == 0 ) ? "" : "," + max.ToString ( ) );
        _sb.Append ( ".{" + count + "}" );
        return this;
    }

    #endregion

    public string Compose ()
    {
        return "(" + _sb.ToString ( ) + ")";
    }
}
Bakudan
fonte
0

Você pode usar a classe abaixo para validação:

public class PasswordValidator{

  private Pattern pattern;
  private Matcher matcher;

  private static final String PASSWORD_PATTERN =
          "((?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%]).{6,20})";

  public PasswordValidator(){
      pattern = Pattern.compile(PASSWORD_PATTERN);
  }

  /**
   * Validate password with regular expression
   * @param password password for validation
   * @return true valid password, false invalid password
   */
  public boolean validate(final String password){

      matcher = pattern.matcher(password);
      return matcher.matches();

  }
}

onde 6 e 20 são os tamanhos mínimo e máximo para a senha.

amit pandya
fonte
0
  • Use uma expressão sem retrocesso para corresponder à senha inteira primeiro, se ela tiver pelo menos 8 caracteres (dessa forma, não há explosão combinatória por muito tempo, mas senhas inválidas): (?>{8,})
  • Use as declarações lookbehind para verificar a presença de todos os caracteres necessários (condições AND). (?<=...)
  • Pelo menos um caractere maiúsculo: (?<=\p{Lu}.*)
  • Pelo menos um caractere especial (um pouco ambíguo, mas vamos usar não palavra): (?<=\W.*)
  • Pelo menos um caractere alfanumérico (: (?<=\w.*)

Resumido:

(?>.{8,})(?<=\p{Lu}.*)(?<=\W.*)(?<=\w.*)

relativamente aleatório
fonte
0

O melhor é não usar regex para tudo. Esses requisitos são muito leves. Em operações de string baseadas na CPU para verificar os critérios / validação é muito mais barato e rápido do que regex!

ANSerpen
fonte
-2
/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}$/
Kailash Karki
fonte
15
Eu sugiro que você edite sua pergunta e inclua alguma explicação. Respostas apenas de código às vezes são boas o suficiente, mas respostas de código + explicação são sempre melhores
Barranka