asp.net - net - tag helper asp for
Obtención de la clave de la máquina ASP.NET actual (9)
Me encuentro con ganas de obtener la clave de la máquina ASP.NET para la aplicación actual. Esto es, por supuesto, fácil si se especifica una clave de máquina en el archivo de configuración, pero si está configurado para generarse automáticamente, no parece haber un método público para obtenerla.
Básicamente quiero hacerlo, así que puedo escribir una cookie cifrada / MAC para mí, como lo hace el proveedor de autenticación de formularios ASP.NET.
¿Alguien tiene algún puntero o ideas?
¿Realmente NECESITAS la llave? ¿O simplemente para cifrar y descifrar los datos?
System.Web.Security.FormsAuthentication (.NET 2.0) tiene métodos públicos de cifrado / descifrado. Estos utilizan System.Web.Configuration.MachineKeySection EncryptOrDecryptData, ByteArrayToHexString y HexStringToByteArray para cifrar y descifrar los datos.
EncryptOrDecryptData maneja la carga / configuración de los datos clave de los archivos de configuración / AutoGenerar según sea necesario.
Cifrar y descifrar debe estar disponible a través de las descargas de código fuente o el reflector y se puede convertir fácilmente a su propósito.
Agregue la siguiente información de configuración a su archivo web.config. Asegúrese de reemplazar la información con su propia información.
<system.web>
<machineKey validationKey="E4451576F51E0562D91A1748DF7AB3027FEF3C2CCAC46D756C833E1AF20C7BAEFFACF97C7081ADA4648918E0B56BF27D1699A6EB2D9B6967A562CAD14767F163"
decryptionKey="6159C46C9E288028ED26F5A65CED7317A83CB3485DE8C592" validation="HMACSHA256" decryption="AES" />
</system.web>
clave de validación y clave de descifrado, la validación y descifrado deben variar según el servidor y el protocolo.
Gracias señor curioso
basado en tus punteros tengo esto:
private byte[] _validationKey;
private byte[] _decryptionKey;
public static byte[] GetKey(object provider, string name)
{
var validationKey = provider.GetType().GetMethod(name).Invoke(provider, new object[0]);
return (byte[])validationKey.GetType().GetMethod("GetKeyMaterial").Invoke(validationKey, new object[0]);
}
protected override void OnLoad(EventArgs e)
{
var machineKey = typeof(MachineKeySection).GetMethods(BindingFlags.Static | BindingFlags.NonPublic).Single(a => a.Name == "GetApplicationConfig").Invoke(null, new object[0]);
var type = Assembly.Load("System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a").GetTypes().Single(a => a.Name == "MachineKeyMasterKeyProvider");
var instance = type.Assembly.CreateInstance(
type.FullName, false,
BindingFlags.Instance | BindingFlags.NonPublic,
null, new object[] { machineKey, null, null, null, null }, null, null);
var validationKey = type.GetMethod("GetValidationKey").Invoke(instance, new object[0]);
var key = (byte[])validationKey.GetType().GetMethod("GetKeyMaterial").Invoke(validationKey, new object[0]);
_validationKey = GetKey(instance, "GetValidationKey");
_decryptionKey = GetKey(instance, "GetEncryptionKey");
}
Para .Net 4.5 aquí está el código
//using System.Reflection
//using System.Web.Configuration
byte[] autogenKeys = (byte[])typeof(HttpRuntime).GetField("s_autogenKeys", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
Type t = typeof(System.Web.Security.DefaultAuthenticationEventArgs).Assembly.GetType("System.Web.Security.Cryptography.MachineKeyMasterKeyProvider");
ConstructorInfo ctor = t.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)[0];
Type ckey = typeof(System.Web.Security.DefaultAuthenticationEventArgs).Assembly.GetType("System.Web.Security.Cryptography.CryptographicKey");
ConstructorInfo ckeyCtor = ckey.GetConstructors(BindingFlags.Instance | BindingFlags.Public)[0];
Object ckeyobj = ckeyCtor.Invoke(new object[] { autogenKeys });
object o = ctor.Invoke(new object[] { new MachineKeySection(), null, null, ckeyobj, null });
var encKey = t.GetMethod("GetEncryptionKey").Invoke(o, null);
byte[] encBytes = ckey.GetMethod("GetKeyMaterial").Invoke(encKey, null) as byte[];
var vldKey = t.GetMethod("GetValidationKey").Invoke(o, null);
byte[] vldBytes = ckey.GetMethod("GetKeyMaterial").Invoke(vldKey, null) as byte[];
string decryptionKey = BitConverter.ToString(encBytes);
decryptionKey = decryptionKey.Replace("-", "");
string validationKey = BitConverter.ToString(vldBytes);
validationKey = validationKey.Replace("-", "");
Se me ocurrió esto como una combinación de las respuestas anteriores para .NET post-4.5. Coloque el código a continuación en un archivo llamado mk.aspx, luego busque el código para obtener la clave. Asegúrate de eliminarlo inmediatamente después, porque esto es malo.
<%@ Import Namespace="System.Reflection" %>
<%@ Import Namespace="System" %>
<%@ Import Namespace="System.Web" %>
<%@ Import Namespace="System.Web.Configuration" %>
<%@ Page Language="C#"%>
<%
byte[] autogenKeys = (byte[])typeof(HttpRuntime).GetField("s_autogenKeys", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
Type t = typeof(System.Web.Security.DefaultAuthenticationEventArgs).Assembly.GetType("System.Web.Security.Cryptography.MachineKeyMasterKeyProvider");
ConstructorInfo ctor = t.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)[0];
Type ckey = typeof(System.Web.Security.DefaultAuthenticationEventArgs).Assembly.GetType("System.Web.Security.Cryptography.CryptographicKey");
ConstructorInfo ckeyCtor = ckey.GetConstructors(BindingFlags.Instance | BindingFlags.Public)[0];
Object ckeyobj = ckeyCtor.Invoke(new object[] { autogenKeys });
object o = ctor.Invoke(new object[] { new MachineKeySection(), null, null, ckeyobj, null });
var encKey = t.GetMethod("GetEncryptionKey").Invoke(o, null);
byte[] encBytes = ckey.GetMethod("GetKeyMaterial").Invoke(encKey, null) as byte[];
var vldKey = t.GetMethod("GetValidationKey").Invoke(o, null);
byte[] vldBytes = ckey.GetMethod("GetKeyMaterial").Invoke(vldKey, null) as byte[];
string decryptionKey = BitConverter.ToString(encBytes);
decryptionKey = decryptionKey.Replace("-", "");
string validationKey = BitConverter.ToString(vldBytes);
validationKey = validationKey.Replace("-", "");
%>
<machineKey
validationKey="<%=validationKey%>"
decryptionKey="<%=decryptionKey%>"
/>
Si el proveedor de autenticación de formularios ASP.NET puede acceder a él, ¿ha intentado buscar el código fuente del proveedor ? (Creo que esta es la ubicación correcta, la publicación original del blog de ScottGu sobre el tema ha tenido enlaces rotos desde que actualizaron MSDN)
Si está utilizando .NET 4, está la clase MachineKey . No le proporciona acceso directo a la clave real, pero sí proporciona métodos para codificar y decodificar los datos utilizando los mismos algoritmos que la clase FormsAuthentication, junto con opciones para agregar validación con un HMAC.
Tuve el mismo problema y necesitaba obtener la clave de la máquina desde una aplicación web en ejecución (que no utilizaba las funciones de criptografía .NET 4.5) a la que no podía hacer un cambio de código, así que creé un archivo simple .aspx que extrae la clave y la descarga. a un archivo y luego lo colocó en la raíz de la aplicación y accedió usando un navegador (sin necesidad de tocar la aplicación en ejecución)
<%@ Page Language="C#"
var runTimeType = typeof(System.Web.HttpRuntime);
var autogenKeysField = runTimeType.GetField("s_autogenKeys", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
var autogenKeys = (byte[])autogenKeysField.GetValue(null);
var machineKeySection = new System.Web.Configuration.MachineKeySection();
var autogenKeyProperty = typeof(System.Web.Configuration.MachineKeySection).GetProperty("AutogenKey", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
var decryptionKeyField = typeof(System.Web.Configuration.MachineKeySection).GetField("_DecryptionKey", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
var validationKeyField = typeof(System.Web.Configuration.MachineKeySection).GetField("_ValidationKey", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
// This needs to be done to make machineKeySection refresh it''s data
var touch = (bool)autogenKeyProperty.GetValue(machineKeySection);
var decryptionKey = (byte[])decryptionKeyField.GetValue(machineKeySection);
var validationKey = (byte[])validationKeyField.GetValue(machineKeySection);
var autogenKeyString = BitConverter.ToString(autogenKeys).Replace("-", string.Empty);
var encryptionKeyString = BitConverter.ToString(decryptionKey).Replace("-", string.Empty);
var validationKeyString = BitConverter.ToString(validationKey).Replace("-", string.Empty);
using (var writer = new System.IO.StreamWriter("c:/somewhere/withwriteaccess/MachineKey.config")) {
writer.Write(string.Format("<?xml version=/"1.0/" encoding=/"UTF-8/"?>/r/n<machineKey decryptionKey=/"{0}/" validationKey=/"{1}/" />", encryptionKeyString, validationKeyString));
}
%>
El Sr. Curious también tenía curiosidad por conseguir la llave de la máquina. Las propiedades en MachineKeySection
no son buenas, ya que se ponen a cero después de la inicialización , lo que sucede antes de que pueda leerlas con reflexión.
Después de investigar un poco en el marco 4.5 actual, resulta que las claves generadas automáticamente se almacenan en la HttpApplication.s_autogenKeys
bytes HttpApplication.s_autogenKeys
. La clave de validación son los primeros 64 bytes, seguidos de 24 bytes de la clave de descifrado.
Si no está optando por el nuevo contenido criptográfico en el framework 4.5, es decir, no configuró <httpRuntime targetFramework="4.5">
en su web.config
(que es el caso si tiene una aplicación que creó con un versión anterior del marco), luego llegas a las claves como esta:
byte[] autogenKeys = (byte[])typeof(HttpRuntime).GetField("s_autogenKeys", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
int validationKeySize = 64;
int decryptionKeySize = 24;
byte[] validationKey = new byte[validationKeySize];
byte[] decryptionKey = new byte[decryptionKeySize];
Buffer.BlockCopy(autogenKeys, 0, validationKey, 0, validationKeySize);
Buffer.BlockCopy(autogenKeys, validationKeySize, decryptionKey, 0, decryptionKeySize);
// This is the IsolateApps bit, which is set for both keys
int pathHash = StringComparer.InvariantCultureIgnoreCase.GetHashCode(HttpRuntime.AppDomainAppVirtualPath);
validationKey[0] = (byte)(pathHash & 0xff);
validationKey[1] = (byte)((pathHash & 0xff00) >> 8);
validationKey[2] = (byte)((pathHash & 0xff0000) >> 16);
validationKey[3] = (byte)((pathHash & 0xff000000) >> 24);
decryptionKey[0] = (byte)(pathHash & 0xff);
decryptionKey[1] = (byte)((pathHash & 0xff00) >> 8);
decryptionKey[2] = (byte)((pathHash & 0xff0000) >> 16);
decryptionKey[3] = (byte)((pathHash & 0xff000000) >> 24);
El valor predeterminado para ambas teclas es AutoGenerate,IsolateApps
; IsolateApps
bit IsolateApps
requiere que copie los primeros cuatro bytes del hash de la ruta de la aplicación al comienzo de la clave.
Si optó por las mejoras criptográficas en fx4.5 , tendrá que buscar en el MachineKeyMasterKeyProvider para obtener las claves válidas.
Obteniendo las claves sin la HttpApplication
HttpApplication
obtiene sus claves llamando a un método nativo en webengine4.dll
desde SetAutogenKeys()
. Podemos llamar a la DLL nosotros también. Todo lo que necesitamos saber es nuestra ruta de aplicación.
Digamos que queremos obtener las claves generadas automáticamente para la aplicación raíz, " /
".
Usando LinqPad:
[DllImport(@"C:/Windows/Microsoft.NET/Framework/v4.0.30319/webengine4.dll")]
internal static extern int EcbCallISAPI(IntPtr pECB, int iFunction, byte[] bufferIn, int sizeIn, byte[] bufferOut, int sizeOut);
void Main()
{
string appPath = "/";
byte[] genKeys = new byte[1024];
byte[] autogenKeys = new byte[1024];
int res = EcbCallISAPI(IntPtr.Zero, 4, genKeys, genKeys.Length, autogenKeys, autogenKeys.Length);
if (res == 1) {
// Same as above
int validationKeySize = 64;
int decryptionKeySize = 24;
byte[] validationKey = new byte[validationKeySize];
byte[] decryptionKey = new byte[decryptionKeySize];
Buffer.BlockCopy(autogenKeys, 0, validationKey, 0, validationKeySize);
Buffer.BlockCopy(autogenKeys, validationKeySize, decryptionKey, 0, decryptionKeySize);
int pathHash = StringComparer.InvariantCultureIgnoreCase.GetHashCode(appPath);
validationKey[0] = (byte)(pathHash & 0xff);
validationKey[1] = (byte)((pathHash & 0xff00) >> 8);
validationKey[2] = (byte)((pathHash & 0xff0000) >> 16);
validationKey[3] = (byte)((pathHash & 0xff000000) >> 24);
decryptionKey[0] = (byte)(pathHash & 0xff);
decryptionKey[1] = (byte)((pathHash & 0xff00) >> 8);
decryptionKey[2] = (byte)((pathHash & 0xff0000) >> 16);
decryptionKey[3] = (byte)((pathHash & 0xff000000) >> 24);
Console.WriteLine("DecryptionKey: {0}", decryptionKey.Aggregate(new StringBuilder(), (acc, c) => acc.AppendFormat("{0:x2}", c), acc => acc.ToString()));
Console.WriteLine("ValidationKey: {0}", validationKey.Aggregate(new StringBuilder(), (acc, c) => acc.AppendFormat("{0:x2}", c), acc => acc.ToString()));
}
}
Obtener las claves de MachineKeyMasterKeyProvider
Se puede acceder a las claves para el nuevo material fx4.5 mediante la creación de una instancia de MachineKeyMasterKeyProvider
con el constructor interno , y luego pasar la matriz de bytes autogenKeys
obtenida como se autogenKeys
en el código anterior. El proveedor tiene los métodos GetEncryptionKey
y GetValidationKey
para obtener las claves reales.