Por ASP clásico / 29/03/2025 @ 16:49:42 / 1220 visitas
El hashing es un proceso criptográfico que convierte una contraseña (o cualquier dato) en una cadena de caracteres única y prácticamente irreversible. A diferencia de la encriptación, que es bidireccional (se puede descifrar), un buen hash no se puede revertir.
* Irreversibilidad: No debe haber forma de obtener la contraseña original a partir del hash.
* Determinista: La misma contraseña siempre genera el mismo hash.
*Resistente a colisiones: Dos contraseñas diferentes no deberían producir el mismo hash.
* Lento (sí, ¡lento!): Los algoritmos modernos están diseñados para ser computacionalmente costosos, lo que dificulta los ataques por fuerza bruta.
En ASP Clásico, aunque no tenemos las librerías más modernas de .NET, podemos implementar soluciones robustas con un poco de ingenio.
Aunque alguna vez fueron populares, hoy son considerados inseguros. Se pueden romper con relativa facilidad usando técnicas como rainbow tables o ataques de colisión.
Son más seguros que MD5, pero siguen siendo rápidos, lo que los hace vulnerables a fuerza bruta si no se usan con salting.
Estos algoritmos están diseñados específicamente para contraseñas:
* PBKDF2 (Password-Based Key Derivation Function 2) aplica múltiples iteraciones de un hash (como SHA-256) junto con una sal (salt) para hacer el proceso más lento y seguro.
* bcrypt es aún mejor, ya que ajusta automáticamente la complejidad según la capacidad del hardware.
Lamentablemente, ASP Clásico no tiene soporte nativo para bcrypt, pero podemos implementar PBKDF2 con un poco de código VBScript y ayuda de librerías externas.
La sal es un valor aleatorio que se añade a la contraseña antes de hacer el hash. Esto evita que dos usuarios con la misma contraseña tengan el mismo hash y protege contra ataques de diccionario.
Function GenerateSalt(length)
Dim chars, salt, i, randomIndex
chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()"
salt = ""
Randomize
For i = 1 To length
randomIndex = Int((Len(chars) * Rnd()) + 1)
salt = salt & Mid(chars, randomIndex, 1)
Next
GenerateSalt = salt
End Function
Para hacer el proceso más seguro, podemos aplicar múltiples iteraciones del hash.
Function HashPassword(password, salt, iterations)
Dim hashedPassword, i
hashedPassword = password & salt
For i = 1 To iterations
hashedPassword = SHA256(hashedPassword) ' Suponiendo que SHA256 es una función disponible
Next
HashPassword = hashedPassword
End Function
Cuando un usuario se registra:
1. Generas una sal única.
2. Aplicas el hash a la contraseña + sal.
3. Guardas el hash resultante y la sal en la base de datos (nunca la contraseña original).
Cuando el usuario inicia sesión:
Recuperas su sal de la BD.
Aplicas el mismo hash a la contraseña ingresada + sal almacenada.
Comparas el resultado con el hash guardado.
Manos a la obra, vemos la forma de hacer el hashing de una contraseña:
<%
' ==============================================
' FUNCIONES PRINCIPALES
' ==============================================
Function GeneratePasswordHash(password)
On Error Resume Next
Dim salt, hashValue
salt = GenerateRandomString(32)
hashValue = CalculateHash(password, salt)
GeneratePasswordHash = hashValue & ":" & salt
If Err.Number <> 0 Then
Response.Write "Error GeneratePasswordHash: " & Err.Description
GeneratePasswordHash = ""
End If
On Error GoTo 0
End Function
Function VerifyPassword(password, storedHashWithSalt)
On Error Resume Next
Dim storedParts, storedHash, storedSalt
storedParts = Split(storedHashWithSalt, ":")
If UBound(storedParts) <> 1 Then
VerifyPassword = False
Exit Function
End If
storedHash = storedParts(0)
storedSalt = storedParts(1)
VerifyPassword = (CalculateHash(password, storedSalt) = storedHash)
If Err.Number <> 0 Then
Response.Write "Error VerifyPassword: " & Err.Description
VerifyPassword = False
End If
On Error GoTo 0
End Function
' ==============================================
' FUNCIONES AUXILIARES
' ==============================================
Function CalculateHash(password, salt)
On Error Resume Next
Dim algorithm, hash, saltedPassword, bytes, hashBytes
algorithm = "SHA512"
saltedPassword = salt & password
Set hash = Server.CreateObject("System.Security.Cryptography.SHA512Managed")
bytes = UTF8Encode(saltedPassword)
hashBytes = hash.ComputeHash_2((bytes))
CalculateHash = BytesToHex(hashBytes)
If Err.Number <> 0 Then
Response.Write "Error CalculateHash: " & Err.Description
CalculateHash = ""
End If
On Error GoTo 0
End Function
Function GenerateRandomString(length)
On Error Resume Next
Dim chars, result, i, randomIndex
chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
Randomize
result = ""
For i = 1 To length
randomIndex = Int((Len(chars) * Rnd()) + 1)
result = result & Mid(chars, randomIndex, 1)
Next
GenerateRandomString = result
If Err.Number <> 0 Then
Response.Write "Error GenerateRandomString: " & Err.Description
GenerateRandomString = ""
End If
On Error GoTo 0
End Function
Function UTF8Encode(str)
On Error Resume Next
Dim stream
Set stream = Server.CreateObject("ADODB.Stream")
stream.Open
stream.Type = 2 ' Text
stream.Charset = "utf-8"
stream.WriteText str
stream.Position = 0
stream.Type = 1 ' Binary
stream.Position = 0
UTF8Encode = stream.Read
stream.Close
Set stream = Nothing
If Err.Number <> 0 Then
Response.Write "Error UTF8Encode: " & Err.Description
UTF8Encode = ""
End If
On Error GoTo 0
End Function
Function BytesToHex(bytes)
On Error Resume Next
Dim hexStr, i, byteVal
hexStr = ""
For i = 1 To LenB(bytes)
byteVal = AscB(MidB(bytes, i, 1))
hexStr = hexStr & Right("0" & Hex(byteVal), 2)
Next
BytesToHex = LCase(hexStr)
If Err.Number <> 0 Then
Response.Write "Error BytesToHex: " & Err.Description
BytesToHex = ""
End If
On Error GoTo 0
End Function
%>
<%
' --------------------------------------------------
' CÓDIGO PARA PROBAR HASHING
' --------------------------------------------------
' 1. Primero genera un hash de una contraseña
Dim miPassword, hashGenerado
miPassword = "hola" ' Cambia esto para probar
hashGenerado = GeneratePasswordHash(miPassword)
Response.Write "Contraseña original: " & miPassword & "
"
Response.Write "Hash generado: " & hashGenerado & "
"
' 2. Luego verifica si otra contraseña coincide
Dim pruebaPassword, esValida
pruebaPassword = "hola" ' Cambia esto para probar (usa una diferente para ver el fallo)
esValida = VerifyPassword(pruebaPassword, hashGenerado)
If esValida Then
Response.Write pruebaPassword & "' ES VÁLIDA (coincide con el hash)"
Else
Response.Write pruebaPassword & "' NO VÁLIDA (no coincide con el hash)"
End If
%>
Aunque ASP Clásico es una tecnología antigua, eso no significa que debamos descuidar la seguridad. Implementar hashing con sal y algoritmos robustos como PBKDF2 puede marcar la diferencia entre una aplicación vulnerable y una que protege adecuadamente a sus usuarios.
Si puedes, usa SSL/TLS para todas las comunicaciones y nunca envíes contraseñas en texto plano por HTTP. ¡Seguridad en capas es la clave!
Descubre más sobre cómo simplificar y optimizar tu trabajo empresarial en el Blog de CoreASP.
hashing, contraseñas, ASP Clásico, seguridad, criptografía, PBKDF2, bcrypt, SHA-256, sal, almacenamiento seguro, ataques, fuerza bruta, rainbow tables, VBScript
Descargo de Responsabilidad:
El contenido y los recursos que ofrecemos en CoreASP están destinados únicamente a proporcionar herramientas y ejemplos prácticos para el desarrollo en ASP Clásico. Esta información es de carácter general y no debe considerarse asesoramiento profesional o técnico específico para tu proyecto. Aunque hacemos todo lo posible por asegurar la calidad y precisión de los recursos compartidos, no garantizamos que sean completamente libres de errores o que se ajusten perfectamente a todas las situaciones. CoreASP no se responsabiliza por cualquier pérdida, daño o inconveniente derivado del uso directo o indirecto de los recursos o información proporcionada. Además, CoreASP no respalda ni asume responsabilidad por enlaces o contenido de terceros que puedan estar referenciados en nuestra plataforma. Todos los derechos de propiedad intelectual sobre el contenido y recursos publicados en CoreASP pertenecen a CoreASP o a sus respectivos propietarios, y su uso está sujeto a las condiciones de la licencia especificada para cada recurso. Nos reservamos el derecho de modificar este descargo de responsabilidad en cualquier momento sin previo aviso. Para más detalles, consulta el documento completo de términos y condiciones.
13/07/2025 @ 10:56:59
23/05/2025 @ 14:09:59
07/04/2025 @ 07:54:51
29/03/2025 @ 16:49:42
12/02/2025 @ 10:15:42
21/01/2025 @ 16:21:11