2012-03-29 4 views
15

두 개의 웹 역할 인스턴스가있는 Windows Azure (최신 2.x OS 버전)에서 실행되는 ASP.NET MVC 2 (.NET 4) 응용 프로그램이 있습니다.정적 Machine Key가있는 경우에도 HttpAntiForgeryException이 임의로 발생하는 이유는 무엇입니까?

우리는 모든 POST 요청에 대해 MVC에서 제공하는 위조 토큰을 사용하며 web.config에서 정적 시스템 키를 설정 했으므로 모든 시스템이 여러 시스템에서 작동하고 재시작 할 수 있습니다. 99.9 %의 경우 완벽하게 작동합니다.

하지만 지금은 "필요한 위조 토큰이 제공되지 않았거나 유효하지 않습니다."라는 메시지와 함께 HttpAntiForgeryException을 기록합니다.

브라우저에서 쿠키가 허용되지 않을 수 있지만 쿠키와 쿠키가 올바르게 사용되고 있는지 확인했습니다.

오류는 다양한 브라우저에서 발생하며 사용자가 작업을 반복해야하거나 일부 데이터가 손실 될 수 있으므로 분명히 사용자에게 문제가됩니다. 즉, 문제를 로컬에서 재현하지 못했지만 Windows Azure에서만 발생합니다.

왜 그런 일이 발생합니까? 우리는 어떻게 그것을 피할 수 있습니까?

+0

(MVC 팀의) 보안 담당자와 확인한 결과 Darin이 맞을 것 같습니다. 사용자 이름이 변경되었을 수도 있습니다. – RickAndMSFT

답변

0

시도 할 수있는 몇 가지 옵션이 있습니다. 컴퓨터로 원격 조작을 시도하고 이벤트 로그를보고이 상황에 대해 더 많은 정보를 얻을 수 있는지 확인할 수 있습니다. 그래도 도움이되지 않으면 DebugDiag 또는 다른 도구를 사용하여 프로세스 덤프를 캡처 할 수 있습니다. DebugDiag를 사용하면이 특정 예외가 발생했을 때 캡처 할 수 있습니다. 그리고 그 일을보고 무슨 일이 일어나고 있는지보세요.

당신이 거기에서 알아낼 수 없다면, 당신이 조사 할 때 도움이되는 Microsoft의 지원 사례를 언제든지 만들 수 있습니다.

7

위조 위조 토큰은 현재 연결된 사용자가 발급 될 때 사용자 이름을 포함합니다. 그리고 유효성을 검증 할 때, 현재 연결된 사용자는 토큰이 발행 될 때 사용 된 사용자와 비교하여 점검됩니다. 예를 들어 사용자가 아직 인증되지 않은 상태에서 위조 위조 토큰을 방출하는 양식이있는 경우 사용자 이름이 저장되지 않습니다. 사용자를 인증하는 양식을 제출하면 토큰이 더 이상 유효하지 않습니다. 로그 아웃하는 경우에도 동일하게 적용됩니다. 여기

처럼 유효성 검사 방법 보이는 방법은 다음과 같습니다

public void Validate(HttpContextBase context, string salt) 
{ 
    string antiForgeryTokenName = AntiForgeryData.GetAntiForgeryTokenName(null); 
    string str2 = AntiForgeryData.GetAntiForgeryTokenName(context.Request.ApplicationPath); 
    HttpCookie cookie = context.Request.Cookies[str2]; 
    if ((cookie == null) || string.IsNullOrEmpty(cookie.Value)) 
    { 
     throw CreateValidationException(); 
    } 
    AntiForgeryData data = this.Serializer.Deserialize(cookie.Value); 
    string str3 = context.Request.Form[antiForgeryTokenName]; 
    if (string.IsNullOrEmpty(str3)) 
    { 
     throw CreateValidationException(); 
    } 
    AntiForgeryData data2 = this.Serializer.Deserialize(str3); 
    if (!string.Equals(data.Value, data2.Value, StringComparison.Ordinal)) 
    { 
     throw CreateValidationException(); 
    } 
    string username = AntiForgeryData.GetUsername(context.User); 
    if (!string.Equals(data2.Username, username, StringComparison.OrdinalIgnoreCase)) 
    { 
     throw CreateValidationException(); 
    } 
    if (!string.Equals(salt ?? string.Empty, data2.Salt, StringComparison.Ordinal)) 
    { 
     throw CreateValidationException(); 
    } 
} 

이를 디버깅하는 한 가지 방법은 소스 코드에서 ASP.NET MVC를 다시 컴파일하고, 만약의 경우 한 입력을 정확하게 기록하는 것입니다 경우를 제외하고 던졌습니다.

+0

ASP.NET MVC 팀의 보안 담당자가 동의합니다. 사용자 이름이 변경되었을 수 있습니다. MVC가 오픈 소스가되었으므로 diagnoistic 브랜치를 만들 수 있습니다. AF 토큰에는 사용자 이름이 포함되어 있지 않습니다. 코드는 사용자 토큰이 쿠키 토큰이 아니라 폼 토큰에서 나왔음을 보여줍니다. – RickAndMSFT

+0

문제는 우리가 ASP.NET 인증을 사용하지 않으며 사용자/신원을 설정하지 않는다는 것입니다. 사용자 이름이 자체적으로 변경 될 수 있습니까? (앱이 Azure의 네트워크 서비스로 실행되는 경우)? –

+0

소스 코드에서 ASP.NET MVC를 다시 컴파일 해보고 위조 확인이 실패한 경우 추적을 시도 했습니까? –

15

최근에이 문제가 발생하여 두 가지 원인이 발견되었습니다.

1. 브라우저는 (즉, antiforgery에있을 것입니다) 서버에 게시물을 수행 캐시 할 수는 페이지가있는 경우

를 캐시 페이지 오픈에서 마지막 세션을 복원하고 사용자가 자신이있다 시작시 마지막 세션을 복원하도록 설정된 브라우저 (이 옵션은 크롬에 있음) 페이지는 캐시에서 렌더링됩니다. 그러나 요청 확인 쿠키는 브라우저 세션 쿠키이므로 브라우저가 닫히면 삭제됩니다. 쿠키가 사라지면 위조 방지 예외가 생깁니다. 해결책 : 페이지가 캐시되지 않도록 응답 헤더를 반환합니다 (예 : 캐시 - 컨트롤 : 비공개, 상점 없음).

2.사이트 시작시 둘 이상의 탭을 여는 경우의 경쟁 조건

브라우저에는 시작할 때 탭 세트를 여는 옵션이 있습니다. 이들 중 둘 이상이 요청 확인 쿠키를 반환하는 사이트를 방문한 경우 요청 확인 쿠키를 덮어 쓰는 경쟁 조건에 부딪 칠 수 있습니다. 요청 확인 쿠키 세트가없는 사용자로부터 둘 이상의 요청이 서버에 도달하기 때문에 이런 일이 발생합니다. 첫 번째 요청이 처리되고 요청 확인 쿠키가 설정됩니다. 다음으로 두 번째 요청이 처리되지만 요청 시간에 아직 설정되지 않은 쿠키를 보내지 않으므로 서버가 새 요청을 생성합니다. 새 페이지가 첫 번째 페이지를 덮어 쓰면 다음 페이지에서 다음에 게시물을 수행 할 때 위조 방지 요청 예외가 발생합니다. MVC 프레임 워크는이 시나리오를 처리하지 않습니다. 이 버그는 Microsoft의 MVC 팀에보고되었습니다.

+0

나는 조건 2도보고있다. 첫 번째 사용자에게만 발생합니다. 첫 번째 사용자가 페이지를로드하면 더 이상 발생하지 않습니다. – GnomeCubed

1

MVC3 웹 응용 프로그램이 꽤 있습니다. 대다수는 클라이언트가 POST 본문을 보내지 않기 때문입니다. 그리고 이들 대부분은 IE8입니다. 왜냐하면 정기적 인 양식 게시를 앞두고있는 ajax 요청의 버그 때문입니다. 종류는 이러한 경우에 클라이언트 버그가 너무 유용한 웹, 아무것도 주변의 문제에 대한 몇 가지 논의가 있지만 있습니다

http://support.microsoft.com/?kbid=831167

것을 증명 증상을 해결하기 위해 보인다 IE를위한 핫픽스가있다 나는 확실히 내가 시도의 다양한 그것을 재현 할 수 적이 없습니다

https://www.google.com/search?q=ie8+empty+post+body

... 어떤 장소에서 제안 된 "솔루션"입니다 연결 유지 시간 제한과 혼란에 대해 아니다 POSTS 사이의 연결을 재설정하므로 실제 정보가 없습니다. IE 빈 POST 시체의 경우 솔루션. 우리가 약간 완화 한 방법은 ajax를 통해 데이터를 검색 할 때 POST 메서드를 사용하지 않도록하는 것입니다.

전체 요청을 로그하는 경우 POST 본문이 비어 있는지 확인하고, 그렇지 않으면 이전 IE가 될 것입니다. 그리고 Content-Length : 0을 의미하지는 않습니다. 일반적으로 Content-Length가 헤더에서 올바르지 만 요청시 헤더 뒤에는 아무 것도 없을 것입니다.

전체적인 문제는 전체 POST 몸체가있는 경우 가끔 예외가 발생하기 때문에 전체적으로 여전히 수수께끼입니다. 우리의 사용자 이름은 절대로 바뀌지 않고 우리의 키도 정적입니다. 소스에 디버깅을 추가하지 않았습니다.

0

나는 집에서 양조 한 위조 방지 코드와 비슷한 문제를 겪었습니다. 이는 개념적으로 MVC 메커니즘과 매우 유사합니다. 대부분의 경우 문제는 현대 브라우저가 캐시되지 않은 것으로 지정된 페이지의 캐시 된 복사본을 표시하고자하기 때문에 발생하는 것으로 보입니다.

나는 페이지 no-cache 지시문의 모든 조합을 시도했지만 때로는 여전히 캐시 된 페이지가 표시됩니다.

더 나은 해결책은 페이지에 대한 onbeforeunload 이벤트를 연결하고 DOM에서 토큰 값을 보유하는 숨겨진 입력 필드의 값을 명시 적으로 지우는 것입니다.

페이지의 캐시 된 사본이로드 된 경우 삭제 된 입력 필드 값이 포함 된 것으로 보입니다. 나는 그 문서 준비 기능이 테스트하고 필요한 경우 페이지를 다시로드 :

window.location.reload(true); 

매우 효과적으로 작동하는 것 같다, 나는 너무 MVC 위조 방지 코드가 의심되는.