문제

ASP.NET 페이지의 CodeHind에서 HMACSHA1 인스턴스를 보유하는 정적 (공유) 변수를 사용하는 것이 위험할지 스스로에게 묻습니다. 문제는 동일한 ASP.NET-PAGE에서 다중 동시 요청을 처리 할 때 모든 ASP.NET Worker-Process의 스레드가 동일한 HMACSHA1 인스턴스를 사용한다는 것입니다. ComputeHash ()가 사용/수정하는 모든 (hmacsha1) instance- 및 computeHash ()- 메소드 변수는 모든 스레드에서 공유 (= 수정 될 수 있음)?! 그 가정이 맞습니까? 결과적으로 ComputeHash의 반환 값은 정확하지 않다고 보장되지 않습니까?!?! 따라서 모든 asp.net-shreads에 정적/공유 hmacsha1- 인스턴스를 사용할 수 없습니다.

이 문제에 대해 어떻게 생각하는지 궁금합니다.

이에 대한 유일한 해결책은 computehash ()-메소드에서 중요한 경로 등과 같은 STH입니다. 그러나 그것은 "우리의 손이 닿지 않는"..

안부, Kris

도움이 되었습니까?

해결책

해싱 알고리즘은 결정적입니다 ~ 해야 하다 매번 주어진 입력에 대해 동일한 해시를 반환하십시오.

매번 동일한 키를 사용하는 한 정적으로 만들 필요가 없습니다. 그러나 매개 변수가없는 생성자로 HMACSHA1 인스턴스를 구성하는 경우 임의의 키를 생성합니다. KeyValue 속성에서 임의의 값을 취하고 해시에 저장해야합니다.

정적 인스턴스를 사용하는 것은 확실히 위험합니다. Thread1이 계산할 값을 설정 한 다음 Thread1이 ComputerHash ()을 호출하기 전에 값을 설정하면 Thread1이 thread2의 값의 해시를 얻게됩니다. 두 스레드가 키를 설정하는 경우에도 마찬가지입니다.

다른 팁

방금 쿼드 코어 HT CPU에서 해시 계산을 수행 한 8 개 또는 16 개의 병렬 작업을 실행할 때 SHA256CNG.comPutehash를 알 수없는 암호화 예외를 얻었습니다.

ComputeHash 주위에 잠금 시맨틱을 추가하면 문제가 해결되었습니다. 따라서 적어도 SHA256CNG 버전은 스레드 안전하지 않은 것 같습니다.

그것을 알아야 할 가치가 있습니다 KeyedHashAlgorithm.ComputeHash() 스레드는 안전하지 않습니다. KeyedHashAlgorithm.Key.

제 경우에는 keyedhashalgorithm 이후 KeyedHashAlgorithm.Key 항상 동일합니다 확실성 클라이언트 측에서. 나는 그것을 알고있다 ComputeHash() 일관성이없고 아마도 내부 변수를 KeyedHashAlgorithm 사례. 스레드 당 인스턴스를 캐시해야합니다 ThreadStatic 또는 ThreadLocal. 이것은 테스트입니다.

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

이 코드는 '스레드 안전'결과에 대한 다른 기능을 테스트하는 데 사용할 수 있습니다. 이것이 다른 사람들에게 도움이되기를 바랍니다.

잠금없이 스레드 안전을 원한다면 스레드 스틱 속성을 사용하여 다음과 같은 각 스레드에서 고유 한 인스턴스를 만들 수 있습니다.

[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. 스레드 정적 필드에 액세스하는 것은 일반 정적 필드에 액세스하는 것보다 훨씬 오래 걸립니다. 따라서 스레드 정적 버전이 더 나을 수도 있고 아닐 수도 있습니다.

  2. 페이지 요청 당 한 번이 작업을 수행하는 경우 차이가 너무 작아서 선택한 접근 방식은 중요하지 않습니다. 매우 단단한 루프 로이 작업을 수행하거나 잠금 섹션의 코드가 오랜 시간이 걸렸다면 선택이 중요 할 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top