Implementación de URL de activación segura y única de "uso único" en ASP.NET(C#)
tsql cryptography (6)
Tengo un escenario en el que los usuarios de un sitio que estoy construyendo necesitan la capacidad de 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 utiliza MSSQL 2005 para sus datos relacionales.
Los usuarios recibirán un correo electrónico desde el sitio, proporcionándoles un enlace único 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 cuando nos registramos en sitios como foros, que contienen un parámetro de URL único generado de forma aleatoria, específicamente relacionado con un solo propósito (como verificar una dirección de correo electrónico para un foro).
Mis consultas están relacionadas con la implementación segura de este problema. Estaba considerando usar un GUID como identificador único, pero no estoy seguro de sus implicaciones en el mundo de la seguridad.
- ¿Un GUID es lo suficientemente largo como para que los valores no se puedan adivinar fácilmente (o se puedan forzar con la brutalidad)?
¿Es la implementación de .NET GUID suficientemente aleatoria en el sentido de que existe la misma posibilidad de generar todos los valores posibles en el "espacio clave"?
Si el uso de un GUID es un enfoque aceptable, ¿debería el sitio redirigirse a la información a través de la reescritura de URL o asociar la información en una base de datos con el GUID como referencia?
¿El uso de una reescritura de URL ocultará la verdadera fuente de los datos?
¿Debo considerar el uso de SELECT NEWID () de TSQL como el generador GUID sobre la implementación de .NET?
¿Estoy completamente equivocado con mi enfoque de este problema?
Muchas gracias,
Carl
- No, los GUID no son completamente aleatorios, y la mayoría de los bits son estáticos o fáciles de adivinar.
- No, no son aleatorios, vea 1. En realidad hay un número muy pequeño de bits que son realmente aleatorios, y no criptográficamente al azar.
- No es, ver 1 y 2.
- Puedes, pero no necesitas ... ver mi solución al final.
- No, ver 1 y 2
- Sí.
Lo que debería usar en lugar de un GUID, es un generador criptográficamente sólido de números aleatorios: use System.Security.Cryptography.RNGCryptoServiceProvider , para generar una cadena de datos larga (por ejemplo, 32 bytes), luego codifique en base64 .
Además, suponiendo que este sea un tipo de registro con datos confidenciales, querrá limitar la validez del enlace, por ejemplo, 60 minutos o 24 horas, dependiendo de su sitio.
Deberá mantener una asignación de estos valores a los usuarios específicos. Luego, puede presentarle automáticamente la forma adecuada según sea necesario. No es necesario realizar la reescritura de URL, solo use eso como el identificador del usuario (en esta página).
Por supuesto, no olvides que esta URL debería ser HTTPS ...
Por cierto, solo una nota: es una buena práctica poner algún tipo de texto en el correo electrónico, explicando que los usuarios no deben hacer clic en los enlaces de los correos electrónicos anónimos, y normalmente su sitio no se envía, y nunca deben ingresar su contraseña después de hacer clic en blablabla ... .
Oh, casi lo olvido, otro problema que debe considerar es qué sucede si el usuario desea que se le envíen varios correos electrónicos, por ejemplo, los registros de visitas varias veces. ¿Puede hacer esto una y otra vez y obtener muchas URL válidas? ¿Sólo el último es válido? ¿O tal vez el mismo valor se vuelve a enviar una y otra vez? Por supuesto, si un usuario anónimo puede enviar una solicitud de este correo electrónico, DoS puede convertirse en un problema ... sin mencionar que si pone su propio correo electrónico, también puede ingresar cualquier dirección aleatoria, inundando a algunos pobres shmuck. bandeja de entrada y posiblemente provocando que su servidor de correo se incluya en la lista negra ...
No hay una respuesta correcta, pero debe considerarse en el contexto de su aplicación.
- Sí, 2 128 es lo suficientemente largo.
- No, las implementaciones de GUID están diseñadas para generar GUID únicos en lugar de aleatorios. Debe usar un generador de números aleatorios seguro criptográficamente (por ejemplo,
RNGCryptoServiceProvider
) para generar 16 bytes aleatorios e inicializar una estructuraGuid
con eso. - Sí, es un enfoque aceptable en general. Ambos funcionarán.
- Sí, si no das ninguna otra pista.
- No
goto 2
- No, está bastante bien. Solo necesita usar un generador de números aleatorios criptográficamente seguro para generar el GUID.
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 de GUID, esto podría no ser una buena idea. Si bien las implementaciones recientes deberían ser "suficientemente buenas por lo general", los valores pueden ser muy previsibles. 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 tiempo desde el inicio. Sin embargo, los valores posibles son limitados, por lo que no tiene 128 bits verdaderos aleatorios.
Si la seguridad es la máxima prioridad, elegiría un generador de números aleatorios criptográficamente sólido y crearía una cadena de caracteres aleatorios. Esto también hace que oyu sea independiente de un algoritmo fácil de adivinar (como guid.ToString () se identifica fácilmente como tal) para lo cual se podría descubrir un ataque en el futuro cercano.
Si se cumplen estos criterios, no veo ningún problema en tener la clave en la cadena de consulta.
Puede ser una exageración, pero puede hash su dirección de correo electrónico con SHA1 usando su guid (NewGuid está bien) como sal de hash y colocarlo en la URL. Luego, cuando llegan a su página, puede pedirles su dirección de correo electrónico, recuperar el guid y volver a calcular el hash para validar. Incluso si alguien supiera qué direcciones de correo electrónico probar, nunca podrían generar una colisión hash sin saber la guía con la que salieron (o les tomaría un infierno de mucho tiempo). Por supuesto, tendría que guardar su correo electrónico y el hash guid en la base de datos.
Recomendaría usar solo un número aleatorio, por ejemplo, bytes de RNGCryptoServiceProvider.GetBytes . Los GUID no están destinados a ser completamente aleatorios. Tienen bits fijos, 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 similar. Es mejor usar POST y asociar el número aleatorio con una fila de su base de datos.
cree una tabla en la base de datos con un linkID y una columna de Datesent, en la generación del enlace envíe inserte DateTime. Ahora en la tabla y devuelva linkId, establezca el linkID como un parámetro de cadena de consulta en el enlace de activación. Al cargar la página de activación, recupere el Id. De enlace y utilícelo para evocar un procedimiento almacenado que devolverá la fecha cuando se haya pasado el Id. De vínculo correspondiente como parámetro. Cuando recupere la fecha, puede agregar cuánto tiempo desea que el vínculo permanezca activo. usando los .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 la duración de días o meses, aparecerá un mensaje de error o, si no, continuará y mostrará el contenido de la página. Le sugiero que mantenga el contenido de la página en un panel y lo establezca vissible = "false", luego haga que el panel sea visible = "true" si la fecha todavía está dentro del rango.