2009-06-02 13 views
21

Tengo un escenario en el que los usuarios de un sitio que estoy creando necesitan poder ingresar información básica en un formulario web sin tener que iniciar sesión. El sitio se está desarrollando con ASP.NET/C# y está utilizando MSSQL 2005 para sus datos relacionales.Implementación de URL de activación seguras y únicas de "uso único" en ASP.NET (C#)

A los usuarios se les enviará un correo electrónico desde el sitio, proporcionándoles un enlace exclusivo para ingresar la información específica que se requiere. El correo electrónico será muy similar al estilo de correo electrónico que todos recibimos al registrar sitios como foros, que contienen un parámetro de URL único generado de forma aleatoria, específicamente relacionado con un único propósito (como verificar una dirección de correo electrónico para un foro).

Mis consultas se refieren a la implementación segura de este problema. Estaba considerando usar un GUID como el identificador único, pero no estoy seguro de sus implicaciones en el mundo de la seguridad.

  1. ¿Es un GUID lo suficientemente largo como para que los valores no puedan adivinarse fácilmente (o forzados en el tiempo)?
  2. ¿La implementación de GUID de .NET es suficientemente aleatoria en el sentido de que existe la misma posibilidad de generación de todos los valores posibles en el "espacio clave"?

  3. Si usar un GUID es un enfoque aceptable, ¿debe el sitio redirigir a la información mediante la reescritura de URL o asociar la información en una tabla de datos con el GUID como referencia?

  4. ¿Utilizará una reescritura de URL para ocultar la verdadera fuente de los datos?

  5. ¿Debo considerar usar el SELECT NEWID() de TSQL como generador de GUID sobre la implementación de .NET?

  6. ¿Estoy completamente equivocado con mi enfoque a este problema?

Muchas gracias,

Carl

Respuesta

12
  1. Sí, 2 es lo suficientemente largo.
  2. No, las implementaciones de GUID están diseñadas para generar GUID únicos en lugar de los aleatorios. Debe usar un generador de números aleatorios cryptographically secure (por ejemplo, RNGCryptoServiceProvider) para generar 16 bytes aleatorios e inicializar una estructura Guid con eso.
  3. Sí, es un enfoque aceptable en general. Ambos funcionarán.
  4. Sí, si no dar otras pistas
  5. No, goto 2
  6. No, es bastante bien. Solo necesita usar un generador de números aleatorios criptográficamente seguro para generar el GUID.
+0

Lo sentimos, pero esto es realmente incorrecto y engañoso: los GUID no son buenos para este tipo de cosas, consulte mi respuesta a continuación. – AviD

+0

GUID, en el sentido de * identificador único * no es realmente adecuado (como mencioné en el n. ° 2). Pero no hay nada que le impida usarlos como un número de 128 bits. –

+0

Pero lo cierto es que no son * realmente * números de 128 bits (a pesar de que se necesitan 128 bits para almacenarlos). De nuevo, demasiado de esto es estático o fácilmente adivinable. Los GUID no tienen uso en identificadores seguros. Lo que el OP necesita es algo seguro, y lo suficientemente largo en el sentido de "128 bits de aleatoriedad", que los GUID no son, ni siquiera cerca. – AviD

4

Recomendaría simplemente usar un número aleatorio simple, p. bytes desde RNGCryptoServiceProvider.GetBytes. Los GUID no están destinados a ser completamente aleatorios. Han corregido bits, y algunas versiones usan su dirección MAC. GetBytes también le da la opción de usar más de 128 bits (aunque eso debería ser suficiente).

Creo que es mejor no poner los datos del usuario en una url. Aunque HTTPS puede protegerlo en tránsito, aún puede estar en el historial del navegador del usuario o tal. Es mejor utilizar POST y asociar el número aleatorio con una fila de su base de datos.

1

Primero, si es posible, debe limitar la fuerza bruta, limitando el rendimiento de la consulta (por ejemplo, intentos limitados por IP por segundo y intentos totales limitados por segundo).

Dependiendo del algoritmo de generación GUID, esto podría no ser una buena idea. Si bien las implementaciones recientes deben ser "lo suficientemente buenas por lo general", puede haber mucha predictibilidad de los valores. Las implementaciones recientes como la que se usa en .NET aplican un hash, de lo contrario, tiene campos claramente identificables para la dirección MAC y el tiempo transcurrido desde el arranque. Sin embargo, los valores posibles son limitados, por lo que no tiene 128 bits aleatorios verdaderos.

Si la seguridad es la máxima prioridad, escogería un cryptographically strong random number generator y construiría una cadena de caracteres aleatorios. Esto también hace que oyu sea independiente de un algoritmo fácilmente adivinable (como un guid.ToString() se identifica fácilmente como tal) para el cual un ataque podría ser descubierto en el futuro cercano.

Si se cumplen estos criterios, no veo ningún problema para tener la clave en la cadena de consulta.

4

Podría ser exagerado, pero podría hash su dirección de correo electrónico con SHA1 usando su guid (NewGuid está bien) como hash salt y colocar eso en la URL. Luego, cuando lleguen a su página, podrían preguntarles su dirección de correo electrónico, recuperar el guid y volver a calcular el hash para validarlo. Incluso si alguien supiera qué direcciones de correo electrónico probar, nunca sería capaz de generar una colisión hash sin conocer la guía con la que se sala (o les tomaría muchísimo tiempo :). Por supuesto, tendría que guardar su correo electrónico y el hash salt guid en la base de datos.

+0

Aunque lo anterior técnicamente respondió mis preguntas directamente, me encanta su idea de implementación. Después de pensarlo he expaneded en él alguna: URL = SHA1 (correo + randomPass + sal) serverHash = SHA1 (correo + randomPass) Columnas de la tabla: serverHash (clave principal) sal El randompass haría también se enviará con la url en el correo electrónico y se usará en el cálculo de la URL original y luego se descartará. Creo en esta implementación no se almacenará información sensible en la base de datos.Es decir, incluso si la tabla de datos sin procesar estuviera expuesta, no se pudo generar la URL a fuerza bruta en la dirección de correo electrónico – Tyst

+1

Me alegra ayudar. Una nota sobre su solución, se abre a un nuevo caso de uso ya que no puede recrear el correo electrónico. Es decir, el usuario solicita y envía un correo electrónico, no hace nada con él, solicita otro y luego hace clic en el enlace en el primer correo electrónico (como estoy seguro, los usuarios hacen cosas así :) Por lo tanto, tendrá que caducar cada ServerHash manteniendo la fecha en que envió el correo electrónico en el DB y dando al usuario un tiempo razonable para responder. –

+0

Sí, gracias. Me doy cuenta de esto. Los correos electrónicos y las URL generados son muy específicos de cada caso y se generan para permitir a los usuarios ahorrar dinero, por lo que probablemente deberían usarlos, pero también implementaré algún tipo de manejo. – Tyst

11
  1. No, los GUID no son completamente aleatorios, y la mayoría de los bits son estáticos o fácilmente adivinables.
  2. No, no son aleatorios, ver 1. En realidad, hay un número muy pequeño de bits que son aleatorios, y no criptográficamente fuertes al azar.
  3. No es, consulte 1 y 2.
  4. puede, pero no necesita ... ver mi solución al final.
  5. No, vea 1 y 2
  6. Sí.

Lo que se debe utilizar en lugar de un GUID, es un generador de números aleatorios criptográficamente fuerte - System.Security.Cryptography.RNGCryptoServiceProvider utilizar, para generar larga (por ejemplo, 32 bytes) de la cadena de datos, entonces base64 encode eso.
Además, suponiendo que se trata de algún tipo de registro con datos confidenciales, le recomendamos limitar la validez del enlace, digamos 60 minutos o 24 horas, dependiendo de su sitio.
Deberá mantener un mapeo de estos valores para los usuarios específicos. Luego puede presentarlo automáticamente con la forma adecuada según sea necesario. No es necesario que reescriba la URL, solo utilícela como el identificador del usuario (en esta página).
Por supuesto, no se olvide este URL debe ser HTTPS ...

Por cierto, sólo una nota - sus buenas prácticas para poner algún tipo de texto en el correo electrónico, explicando que los usuarios shouldnt clic en enlaces en correos electrónicos anónimos, y normalmente su sitio no enviará, y nunca deberían ingresar su contraseña después de hacer clic en blablabla ....

Ah, casi lo olvidaste, otro problema que debes tener en cuenta es lo que sucede si el usuario quiere que se le envíen varios correos electrónicos, p. los hits se registran varias veces ¿Puede hacer esto una y otra vez y obtener muchas URL válidas? ¿Es solo el último válido? ¿O tal vez el mismo valor se resiente una y otra vez? Por supuesto, si un usuario anónimo puede enviar una solicitud para este correo electrónico, DoS puede convertirse en un problema ... sin mencionar que si ingresa su propio correo electrónico, también puede ingresar cualquier dirección aleatoria, inundando algunos pobres shmuck's bandeja de entrada y posiblemente hacer que su servidor de correo sea incluido en la lista negra ...
No hay una respuesta correcta, pero debe considerarse en el contexto de su aplicación.

-1

cree una tabla en la base de datos con un linkID y una columna Datesent, en la generación de la inserción de envío de enlace DateTime.Now en la tabla y devuelva linkId, configure el linkID como un parámetro querystring en activationLink. Al cargar la página de activación recupera el ID de enlace y lo usa para evocar un procedimiento almacenado que devolverá la fecha cuando pasó el ID de enlace correspondiente como parámetro, cuando recuperes la fecha puedes agregar cuánto tiempo quieres que el enlace permanezca activo por utilizando .AddDays() /. AddMonths, estos son métodos de C# para datetime. luego compara la fecha en que regresaste con la fecha de hoy. si ha pasado su duración de días o meses, dé un mensaje de error o continúe y muestre el contenido de la página. Supongo que conserva el contenido de la página en un panel y lo configura vissible = "false" y luego solo hace que el panel sea visible = "verdadero" si la fecha todavía está dentro del rango.

Cuestiones relacionadas