2010-07-09 31 views
9

No soy tan moderno en el L33t idioma más allá de lo que he leído en Wikipedia.Convertir leet-speak a texto claro

Necesito agregar una verificación de diccionario a nuestra herramienta de validación de la fortaleza de la contraseña, y dado que leet-speak solo agrega una sobrecarga trivial al proceso de descifrado de la contraseña, me gustaría de-leet-ify la entrada antes de verificar contra el diccionario.

Para aclarar el razonamiento detrás de esto: cuando se requiera agregar símbolos a sus contraseñas, muchos usuarios simplemente harán una sustitución de leet muy predecible en una palabra común para cumplir con el requisito de número y símbolo de inclusión. Debido a que es tan predecible, esto agrega muy poca complejidad real a la contraseña con solo usar la palabra del diccionario original. \ Edit

No se conocen todas las reglas, especialmente las sustituciones de caracteres múltiples como "//" para "W", y estoy seguro de que este es un problema que ha sido abordado muchas veces, incluso por proyectos de código abierto.

Estoy buscando ejemplos de código, pero no he encontrado ninguno hasta ahora. Si es C# código que sería una ventaja !, pero el código en cualquier idioma común ayudará.

Además, sería bueno tener un enfoque extensible, ya que entiendo que este dialecto evoluciona rápidamente. Sería bueno poder agregar algunas reglas en un año a medida que evolucionan.

Y no, esta no es la base de mi verificación completa de la contraseña. Esta es solo la parte en la que solicito ayuda en esta publicación. Así que no nos distraemos con otros elementos de contraseña y problemas de seguridad, permítanme describir los problemas de contraseña que no tienen que ver con leet-speak:

Medimos los bits de entropía en la contraseña por NIST special publication 800-63, y requerimos una medida equivalente configurable por política (56 bits por ejemplo) para que la contraseña sea válida. Esto todavía deja espacio para las palabras del diccionario que simplemente han sido editadas y desde una perspectiva de entropía no son mucho mejores las palabras del diccionario.

Simplemente me gustaría decir a los usuarios que "P @ s5w0rd" es una palabra del diccionario demasiado cercana, y que probablemente puedan encontrar una contraseña más segura.

Sé que hay mucho más por consideraciones de seguridad como el equilibrio entre las contraseñas que los humanos pueden recordar y las contraseñas que son seguras. Esta no es esa pregunta.

Todo lo que estoy preguntando es la conversión de l33t a texto sin formato, que debería ser casi tan divertido e interesante de un tema como el código de golf. ¿Alguien ha visto alguna muestra de código?

+1

He puesto en una respuesta un poco más complicado, que resuelve el xkcd "Tr0ub4dor y 3" contraseña. –

Respuesta

9

también ofrece algo de código:

String password = @"\/\/4573Fu|_"; 
Dictionary<string, string> leetRules = new Dictionary<string, string>(); 

leetRules.Add("4", "A"); 
leetRules.Add(@"/\", "A"); 
leetRules.Add("@", "A"); 
leetRules.Add("^", "A"); 

leetRules.Add("13", "B"); 
leetRules.Add("/3", "B"); 
leetRules.Add("|3", "B"); 
leetRules.Add("8", "B"); 

leetRules.Add("><", "X"); 

leetRules.Add("<", "C"); 
leetRules.Add("(", "C"); 

leetRules.Add("|)", "D"); 
leetRules.Add("|>", "D"); 

leetRules.Add("3", "E"); 

leetRules.Add("6", "G"); 

leetRules.Add("/-/", "H"); 
leetRules.Add("[-]", "H"); 
leetRules.Add("]-[", "H"); 

leetRules.Add("!", "I"); 

leetRules.Add("|_", "L"); 

leetRules.Add("_/", "J"); 
leetRules.Add("_|", "J"); 

leetRules.Add("1", "L"); 

leetRules.Add("0", "O"); 

leetRules.Add("5", "S"); 

leetRules.Add("7", "T"); 

leetRules.Add(@"\/\/", "W"); 
leetRules.Add(@"\/", "V"); 

leetRules.Add("2", "Z"); 

foreach (KeyValuePair<string,string> x in leetRules) 
{ 
    password = password.Replace(x.Key, x.Value); 
} 

MessageBox.Show(password.ToUpper()); 
+0

Creo que un mapa leet => unleet sería mejor, ya que no tendrías que escribir leetRules.Add para cada par. – tstenner

+0

Gracias, eso es perfecto. Extensible, simple. Estas sustituciones podrían estar en un archivo para hacerlo aún más extensible. Los sufijos como -xor y -zorz podrían simplemente eliminarse. ¿No hay nada más que solo este cifrado de sustitución? ¿Antieconómico? Interesante elección de contraseña. – DanO

+0

Pensé que podría haber más gramática involucrada con leet que simplemente sustitución. Tratar con gramáticas era una parte de CS que no me importaba. – DanO

14

Debo decir que creo que esta es una mala idea ... Si quiere que sean fuertes, proponga mejores requisitos ... deben tener al menos 8 caracteres, contener letras mayúsculas y minúsculas, contener al menos un número , y al menos un personaje especial. Implemente un contador de fallas de autorización máximo antes de deshabilitar una cuenta. Una vez hecho esto, ¿qué te preocupa?

+2

+1 para una mejor dirección, principios de seguridad más relevantes. – andyortlieb

+0

Tengo que decir, estoy de acuerdo :) "De-1337-ifying" no es para nada trivial. Un ejemplo rápido sería que '4' == 'a' en 1337, entonces, ¿quieres deshabilitar los 4? – cwap

+0

Creo que el operador quiere evitar contraseñas como "l33t haxx0r", que es bastante trivial y probablemente bastante común. Tiene 8 caracteres, al menos un número y un carácter especial, pero no es seguro. –

2

¿Por qué no acaba de implementar una función que acaba de crear "pronounceable" passwords y requieren que los usuarios utilizan? Parece mucho menos trabajo y mejor seguridad.

+0

Esta es una buena sugerencia, y una idea interesante, ya que las contraseñas generadas por los usuarios tienen problemas inherentes la mayor parte del tiempo. Sin embargo, en este caso, los usuarios deben poder elegir su propia contraseña, y solo debemos asegurarnos de que sea lo suficientemente fuerte. Esa es una gran idea para ofrecer si quieren ayuda para encontrar una contraseña. – DanO

2

Estoy encontrando la pregunta interesante así que aquí hay una respuesta adicional como ejercicio intelectual; dado que leet speak no se puede mapear con una palabra única, debe examinar los posibles valores decodificados que puede proporcionar una cadena de conversación leet. Aquí algunos ejemplos de código:

public class LeetSpeakDecoder 
{ 
    private Dictionary<string, IEnumerable<string>> Cache { get; set; } 
    private Dictionary<string, string> Rules { get; set; } 

    public LeetSpeakDecoder() 
    { 
     Cache = new Dictionary<string, IEnumerable<string>>(); 
     Rules = new Dictionary<string,string>(); 

     Rules.Add("4", "A"); 
     // add rules here... 
    } 

    public IEnumerable<string> Decode(string leet) 
    { 
     var list = new List<string>(); 
     if (Cache.ContainsKey(leet)) 
     { 
      return Cache[leet]; 
     } 

     DecodeOneCharacter(leet, list); 
     DecodeMoreThanOneCharacter(leet, list); 
     DecodeWholeWord(leet, list); 

     list = list.Distinct().ToList(); 

     Cache.Add(leet, list); 
     return list; 
    } 

    private void DecodeOneCharacter(string leet, List<string> list) 
    { 
     if (leet.Length == 1) 
     { 
      list.Add(leet); 
     } 
    } 

    private void DecodeMoreThanOneCharacter(string leet, List<string> list) 
    { 
     if (leet.Length > 1) 
     { // we split the word in two parts and check how many variations each part will decode to 
      for (var splitPoint = 1; splitPoint < leet.Length; splitPoint++) 
      { 
       foreach (var leftPartDecoded in Decode(leet.Substring(0, splitPoint))) 
       { 
        foreach (var rightPartDecoded in Decode(leet.Substring(splitPoint))) 
        { 
         list.Add(leftPartDecoded + rightPartDecoded); 
        } 
       } 
      } 
     } 
    } 

    private void DecodeWholeWord(string leet, List<string> list) 
    { 
     if (Rules.ContainsKey(leet)) 
     { 
      list.Add(Rules[leet]); 
     } 
    } 
} 

El código considera que

  • un personaje puede mantenerse como está (DecodeOneCharacter)
  • una palabra debe ser decodificada por la combinación de los valores decodificados para toda la posibles divisiones de la palabra (DecodeMoreThanOneCharacter)
  • una palabra deben ser decodificados directamente contra las reglas (DecodeWholeWord)

El almacenamiento en caché es muy útil ya que el código es bastante ineficiente para rastrear qué permutaciones son inútiles: dividir "desperdicio" en "w" y "asteful" o en "wa" y "steful" dará lugar a algunas repeticiones de la decodificación a la derecha, luego a la izquierda. No tengo mucha información, pero se usó regularmente para más del 90% de las decodificaciones; no está mal para una pequeña adición.

Dado que devuelve una combinación de todas las posibles cadenas decodificadas de leet, puede que desee echarle un vistazo para su solución: por ejemplo, el código de Fosco decodificará "137M3P455" a "BTMEPASS", pero es posible que desee saberlo también se traduce como "LETMEPASS", lo que debería hacer que te encojas un poco más.

+0

Vea mi versión mejorada a continuación en función de su inicio. –

2

Según la respuesta de samy anterior, aquí hay una versión mejorada aún más. Permite múltiples reglas de salida por char de entrada, y en particular tiene reglas establecidas para todos los caracteres no alfanuméricos que se eliminan de la cadena. El resultado es que puede enviar la contraseña de cómic XKCD clásica de Tr0ub4dor & 3 y salir de Troubador.

Lo estoy usando para el mismo propósito que el OP, para confirmar que la contraseña proporcionada a mi sistema que contiene datos altamente seguros no se basa en una palabra de diccionario.

Estoy tomando la salida de la función de decodificación y ejecutándola a través de un diccionario.

public class LeetSpeakDecoder 
    { 
     private Dictionary<string, IEnumerable<string>> Cache { get; set; } 
     private Dictionary<string, List<string>> Rules = new Dictionary<string, List<string>>(); 

     public void AddRule(string key, string value) 
     { 
      List<string> keyRules = null; 
      if (Rules.ContainsKey(key)) 
      { 
       keyRules = Rules[key]; 
      } 
      else 
      { 
       keyRules = new List<string>(); 
       Rules[key] = keyRules; 
      } 
      keyRules.Add(value); 
     } 

     public LeetSpeakDecoder() 
     { 
      Cache = new Dictionary<string, IEnumerable<string>>(); 


      AddRule("4", "A"); 
      AddRule("4", "a"); 
      AddRule(@"/\", "A"); 
      AddRule("@", "A"); 
      AddRule("^", "A"); 
      AddRule("13", "B"); 
      AddRule("/3", "B"); 
      AddRule("|3", "B"); 
      AddRule("8", "B"); 
      AddRule("><", "X"); 
      AddRule("<", "C"); 
      AddRule("(", "C"); 
      AddRule("|)", "D"); 
      AddRule("|>", "D"); 
      AddRule("3", "E"); 
      AddRule("6", "G"); 
      AddRule("/-/", "H"); 
      AddRule("[-]", "H"); 
      AddRule("]-[", "H"); 
      AddRule("!", "I"); 
      AddRule("|_", "L"); 
      AddRule("_/", "J"); 
      AddRule("_|", "J"); 
      AddRule("1", "L"); 
      AddRule("0", "O"); 
      AddRule("0", "o"); 
      AddRule("5", "S"); 
      AddRule("7", "T"); 
      AddRule(@"\/\/", "W"); 
      AddRule(@"\/", "V"); 
      AddRule("2", "Z"); 

      const string nonAlpha = @"[email protected]#$%^&*()-_=+[]{}\|;:'<,>./?"""; 
      foreach (var currentChar in nonAlpha) 
      { 
       AddRule(currentChar.ToString(), ""); 
      } 
     } 

     public IEnumerable<string> Decode(string leet) 
     { 
      var list = new List<string>(); 
      if (Cache.ContainsKey(leet)) 
      { 
       return Cache[leet]; 
      } 

      DecodeOneCharacter(leet, list); 
      DecodeMoreThanOneCharacter(leet, list); 
      DecodeWholeWord(leet, list); 

      list = list.Distinct().ToList(); 

      Cache.Add(leet, list); 
      return list; 
     } 

     private void DecodeOneCharacter(string leet, List<string> list) 
     { 
      if (leet.Length == 1) 
      { 
       list.Add(leet); 
      } 
     } 

     private void DecodeMoreThanOneCharacter(string leet, List<string> list) 
     { 
      if (leet.Length > 1) 
      { // we split the word in two parts and check how many variations each part will decode to 
       for (var splitPoint = 1; splitPoint < leet.Length; splitPoint++) 
       { 
        foreach (var leftPartDecoded in Decode(leet.Substring(0, splitPoint))) 
        { 
         foreach (var rightPartDecoded in Decode(leet.Substring(splitPoint))) 
         { 
          list.Add(leftPartDecoded + rightPartDecoded); 
         } 
        } 
       } 
      } 
     } 

     private void DecodeWholeWord(string leet, List<string> list) 
     { 
      if (Rules.ContainsKey(leet)) 
      { 
       foreach (var ruleValue in Rules[leet]) 
       { 
        list.Add(ruleValue); 
       } 

      } 
     } 
    } 

Aquí está mi salida

Tr0ub4dor&3 
Tr0ub4dor&E 
Tr0ub4dor& 
Tr0ub4dor3 
Tr0ub4dorE 
Tr0ub4dor 
Tr0ubAdor&3 
Tr0ubAdor&E 
Tr0ubAdor& 
Tr0ubAdor3 
Tr0ubAdorE 
Tr0ubAdor 
Tr0ubador&3 
Tr0ubador&E 
Tr0ubador& 
Tr0ubador3 
Tr0ubadorE 
Tr0ubador 
Tr0ubdor&3 
Tr0ubdor&E 
Tr0ubdor& 
Tr0ubdor3 
Tr0ubdorE 
Tr0ubdor 
TrOub4dor&3 
TrOub4dor&E 
TrOub4dor& 
TrOub4dor3 
TrOub4dorE 
TrOub4dor 
TrOubAdor&3 
TrOubAdor&E 
TrOubAdor& 
TrOubAdor3 
TrOubAdorE 
TrOubAdor 
TrOubador&3 
TrOubador&E 
TrOubador& 
TrOubador3 
TrOubadorE 
TrOubador 
TrOubdor&3 
TrOubdor&E 
TrOubdor& 
TrOubdor3 
TrOubdorE 
TrOubdor 
Troub4dor&3 
Troub4dor&E 
Troub4dor& 
Troub4dor3 
Troub4dorE 
Troub4dor 
TroubAdor&3 
TroubAdor&E 
TroubAdor& 
TroubAdor3 
TroubAdorE 
TroubAdor 
Troubador&3 
Troubador&E 
Troubador& 
Troubador3 
TroubadorE 
Troubador 
Troubdor&3 
Troubdor&E 
Troubdor& 
Troubdor3 
TroubdorE 
Troubdor 
Trub4dor&3 
Trub4dor&E 
Trub4dor& 
Trub4dor3 
Trub4dorE 
Trub4dor 
TrubAdor&3 
TrubAdor&E 
TrubAdor& 
TrubAdor3 
TrubAdorE 
TrubAdor 
Trubador&3 
Trubador&E 
Trubador& 
Trubador3 
TrubadorE 
Trubador 
Trubdor&3 
Trubdor&E 
Trubdor& 
Trubdor3 
TrubdorE 
Trubdor 
+1

Como un lado interesante Troubador es en realidad deletreado trovador, por lo que la prueba anterior no funciona cuando se compara con un diccionario normal. He agregado varias reglas adicionales en mi conversión, para tratar con ismos británicos, más reglas de leet y errores tipográficos comunes. Cada regla nueva aumenta drásticamente el número de combinaciones, pero como los cambios de contraseña son relativamente infrecuentes, la carga de hacer las permutaciones y la búsqueda del diccionario para cada permutación no son un problema –