Получение текущего машинного ключа ASP.NET - PullRequest
16 голосов
/ 18 ноября 2009

Я хочу получить машинный ключ ASP.NET для текущего приложения. Это, конечно, легко, если в файле конфигурации указан машинный ключ, но если он настроен на автоматическую генерацию, то, похоже, нигде нет публичного метода его получения.

По сути, я хочу, чтобы я мог написать зашифрованный / MAC-файл cookie для себя, как это делает поставщик проверки подлинности с помощью форм ASP.NET.

У кого-нибудь есть указания или идеи?

Ответы [ 9 ]

12 голосов
/ 21 марта 2014

г. Любопытно было любопытно получить ключ от машины. Свойства на MachineKeySection не годятся, так как они обнуляются после инициализации , которая происходит до того, как вы сможете прочитать их с отражением.

После небольшого копания в текущей платформе 4.5 выясняется, что автоматически сгенерированные ключи хранятся в HttpApplication.s_autogenKeys байтовом массиве. Ключ проверки - это первые 64 байта, за которыми следуют 24 байта ключа дешифрования.

Если вы не включили новые крипто-компоненты в 4.5 framework, то есть вы не установили <httpRuntime targetFramework="4.5"> в своем web.config (что имеет место, если у вас есть приложение, которое вы создали с предыдущей версией рамок), то вы попадаете на следующие ключи:

        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);

Значением по умолчанию для обеих клавиш является AutoGenerate,IsolateApps; бит IsolateApps требует, чтобы вы скопировали первые четыре байта хэша пути приложения в начало ключа.

Если вы включили криптографические улучшения в fx4.5 , вам придется копаться в MachineKeyMasterKeyProvider , чтобы получить действительные ключи.

Получение ключей без HttpApplication

HttpApplication получает свои ключи, вызывая собственный метод в webengine4.dll из SetAutogenKeys(). Мы можем сами вызвать DLL. Все, что нам нужно знать, это путь к нашему приложению.

Допустим, мы хотим получить автоматически сгенерированные ключи для корневого приложения "/".

Использование 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()));
    }
}

Получение ключей от MachineKeyMasterKeyProvider

Ключи для нового материала fx4.5 доступны путем создания экземпляра MachineKeyMasterKeyProvider с внутренним конструктором , а затем передачи массива байтов autogenKeys, полученного, как в коде выше. У провайдера есть методы GetEncryptionKey и GetValidationKey, чтобы получить действительные ключи.

5 голосов
/ 04 октября 2011

Если вы используете .NET 4, есть класс MachineKey . Он не дает вам необработанного доступа к фактическому ключу, но он предоставляет методы для кодирования и декодирования данных с использованием тех же алгоритмов, что и класс FormsAuthentication, а также варианты добавления проверки с HMAC.

4 голосов
/ 12 марта 2016

Для .Net 4.5 вот код

//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("-", "");
3 голосов
/ 10 августа 2015

Спасибо, мистер Любопытный,

на основе ваших указателей я получил это:

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");
}
1 голос
/ 29 сентября 2018

Я придумал это как комбинацию ответов выше для пост-4.5 .NET. Перетащите приведенный ниже код в файл с именем mk.aspx, затем перейдите к нему, чтобы получить ключ. Обязательно удалите его сразу после этого, потому что это зло.

<%@ 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%>"
/>
1 голос
/ 18 ноября 2009

Если поставщик проверки подлинности с помощью форм ASP.NET может получить к нему доступ, то пытались ли вы просмотреть исходный код поставщика ? (я думаю, что это правильное местоположение, Исходное сообщение ScottGu в блоге на эту тему имеет неработающие ссылки с момента обновления MSDN)

0 голосов
/ 29 ноября 2017

У меня была та же проблема, и мне нужно было получить машинный ключ из работающего веб-приложения (без использования криптографических функций .NET 4.5), в который я не смог внести изменения в код, поэтому я создал простой файл .aspx, который извлекает ключ и выводит его в файл, а затем помещает его в корень приложения и обращается к нему с помощью браузера (без необходимости прикасаться к запущенному приложению)

<%@ 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));
}
%>
0 голосов
/ 21 августа 2015

Добавьте следующую информацию о конфигурации в ваш файл web.config. Убедитесь, что вы заменили информацию своей собственной информацией.

<system.web>
<machineKey validationKey="E4451576F51E0562D91A1748DF7AB3027FEF3C2CCAC46D756C833E1AF20C7BAEFFACF97C7081ADA4648918E0B56BF27D1699A6EB2D9B6967A562CAD14767F163" 
            decryptionKey="6159C46C9E288028ED26F5A65CED7317A83CB3485DE8C592" validation="HMACSHA256" decryption="AES" />
</system.web>

Ключ проверки и ключ дешифрования, проверка и дешифрование должны различаться в зависимости от вашего сервера и протокола.

0 голосов
/ 23 октября 2010

Вам действительно нужен ключ? Или просто зашифровать и расшифровать данные?

System.Web.Security.FormsAuthentication (.NET 2.0) имеет публичные методы шифрования / дешифрования. Они используют System.Web.Configuration.MachineKeySection EncryptOrDecryptData, ByteArrayToHexString и HexStringToByteArray для шифрования и дешифрования данных.

EncryptOrDecryptData обрабатывает загрузку / настройку данных ключа из конфигурационных файлов / AutoGenerate по мере необходимости.

Шифрование и дешифрование должно быть доступно через загрузку исходного кода или рефлектор и должно быть легко преобразовано для вашей цели.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...