2009-02-20 8 views
4

Я спрашиваю себя, было бы опасно использовать код страницы asp.net, чтобы использовать статическую (общую) переменную, которая содержит экземпляр HMACSHA1. проблема в том, что один и тот же экземпляр HMACSHA1 будет использоваться всеми потоками рабочего процесса asp.net при обработке нескольких одновременных запросов на одной и той же странице asp.net. все (HMACSHA1) экземпляры и ComputeHash() - переменные метода, которые используются/изменены ComputeHash(), будут разделены (= могут быть изменены) всеми потоками ?! это предположение верно? В результате возвращаемое значение ComputeHash не будет гарантировано правильным?!?! , таким образом, мне не разрешено использовать статический/Shared HMACSHA1-экземпляр поверх всех asp.net-потоков.HMACSHA1.ComputeHash() вопрос о безопасности нитей

Мне просто интересно, что вы думаете об этой проблеме.

Единственное решение для этого было бы как критический путь и т. Д. В методе ComputeHash(). но это «вне нашей досягаемости» ..

С уважением, Kris

ответ

4

алгоритмов хеширования являются детерминированными, они должны вернуть ту же хэш для данного входа каждый раз.

Если вы используете один и тот же ключ каждый раз, тогда нет необходимости делать их статичными. Однако, если вы создаете экземпляр HMACSHA1 без конструктора без параметров, он генерирует случайный ключ. Вы должны брать случайное значение из свойства KeyValue и хранить его с помощью хэша.

Определенно опасно использовать статический экземпляр. Если Thread1 задает значение для вычисления, а затем Thread2 устанавливает значение до того, как Thread1 вызовет ComputerHash(), тогда Thread1 получит хэш значения Thread2. То же самое произойдет, если нить устанавливает ключ.

+1

Хеширование алгоритмов действительно должно быть детерминированным .. но проблема в многопоточности :) Как это понимать: «..не нужно сделать их статическими»? Ключ остается тем же самым все время и будет периодически (ежемесячно) изменен. Я создаю экземпляр следующим образом: HMAC hmac = HMAC.Create ("HMACSHA1"); – 2009-02-20 14:42:27

+0

Причина, по которой я делал бы статическую переменную HMAC статикой в ​​классе asp.net-codebehind, - это производительность .. но в противном случае ComputeHash() должен иметь почти около 100% своего контента между критическим разделом, чтобы гарантировать thread-safety .. – 2009-02-20 14:44:44

+0

... моя идея удержать экземпляр hmac как статический была бы хороша для экономии памяти, возможно, но каждый запрос страницы займет больше времени, чем при нестатических hmac-экземплярах из-за механизма блокировки. – 2009-02-20 14:47:09

7

Я получил неизвестное криптографическое исключение из SHA256Cng.ComputeHash при запуске 8 или 16 параллельных задач, которые, помимо прочего, выполняли хэш-вычисления на четырехъядерном процессоре HT cpu.

Добавление смысловой семантики вокруг ComputeHash решило проблему - так что, по крайней мере, версия SHA256Cng не является потокобезопасной.

1

Если вы хотите безопасность потока без блокировки, вы можете использовать ThreadStatic атрибут, чтобы создать уникальный экземпляр на каждом потоке, как это:

[ThreadStatic] 
private static HMACSHA1 _hmacSha1; 

public static HMACSHA1 HmacSha1 
{ 
    get 
    { 
     if (_hmacSha1 == null) 
     { 
      // this will happen once on each thread 
      _hmacSha1 = new HMACSHA1(GetKeyBytes()); 
     }    

     return _hmacSha1; 
    } 
} 

Теперь, две боковые ноты:

  1. ACCESSING поток-статическое поле занимает значительно больше времени, чем доступ к нормальному статическому полю. Таким образом, поточно-статическая версия может или не может быть лучше для вас.

  2. Если вы делаете это один раз на странице запроса, разница будет настолько незначительной, что не имеет значения, какой подход вы выберете. Если вы делаете это в очень сложном цикле или код в секции блокировки занимает очень много времени, выбор может быть важным.

2

Это стоит знать, что KeyedHashAlgorithm.ComputeHash() не поточно, потому что это дает недетерминированное результат для той же KeyedHashAlgorithm.Key.

В моем случае, я хочу, чтобы кэшировать KeyedHashAlgorithm, так как мой KeyedHashAlgorithm.Key всегда одинаково для проверки подлинности со стороны клиента. Я понимаю, что ComputeHash() несовместим, вероятно, он кэширует внутреннюю переменную в экземпляр KeyedHashAlgorithm. Я должен кэшировать экземпляр в потоке ThreadStatic или ThreadLocal. Это испытание:

Static KeyedHashAlgorithm дает противоречивый результат:

var kha = KeyedHashAlgorithm.Create("HMACSHA256"); 
kha.Key = Encoding.UTF8.GetBytes("key"); 
Action comp =() => 
{ 
    var computed = kha.ComputeHash(Encoding.UTF8.GetBytes("message")); 
    Console.WriteLine(Convert.ToBase64String(computed)); 
}; 
Parallel.Invoke(comp, comp, comp, comp, comp, comp, comp, comp); 

По сравнению с KeyedHashAlgorithm в теме:

ThreadLocal<KeyedHashAlgorithm> tl= new ThreadLocal<KeyedHashAlgorithm>(() => 
{ 
    var kha = KeyedHashAlgorithm.Create("HMACSHA256"); 
    kha.Key = Encoding.UTF8.GetBytes("key"); 
    return kha; 
}); 
Action comp =() => 
{ 
    var computed = tl.Value.ComputeHash(Encoding.UTF8.GetBytes("message")); 
    Console.WriteLine(Convert.ToBase64String(computed)); 
}; 
Parallel.Invoke(comp, comp, comp, comp, comp, comp, comp, comp); 

Этот код можно использовать для тестирования других функций для результата «ниточный» , Надеюсь, это поможет другим.

+0

Эй, я искал непоследовательную функцию результата. Если вы обновите HashAlgorithm внутри действия «comp», а не снаружи, он снова будет последовательным. Вы знаете, почему это так? – CRice

+0

Прошло некоторое время. Я не очень много помнил. Вы экспериментируете с кодом. Попытайтесь понять Parallel.Invoke. Если вы инициируете новый HashAlgorithm внутри comp, он будет таким же, как вы его создаете каждый раз, когда хотите его использовать. Поражение цели OP для кэширования экземпляра. Основываясь на моем коде выше, я могу кэшировать один экземпляр для каждого потока, чтобы получить согласованный результат. – CallMeLaNN

Смежные вопросы