잘못된 viewstate 문제 해결

이 문서에서는 디버깅 및 Microsoft ASP.NET 애플리케이션의 viewstate 문제를 해결하는 기술을 소개합니다.

원래 제품 버전: ASP.NET
원래 KB 번호: 829743

소개

Viewstate는 페이지가 서버 상태(예: 세션 상태)를 사용하지 않고도 상태를 자동으로 유지할 수 있도록 하는 ASP.NET 기능입니다. 그러나 viewstate와 관련된 문제는 디버그하기 어려울 수 있습니다. 대부분의 경우 viewstate에 문제가 발생하면 웹 브라우저에서 문제를 일으킬 수 있는 오류 메시지가 거의 표시되지 않습니다.

viewstate가 이 페이지에 유효하지 않으며 손상되었을 수 있습니다.

이 문서에서는 디버깅 및 viewstate 문제 해결에 사용할 수 있는 몇 가지 기술에 대해 설명합니다.

웹 팜에서 실행 중인 경우 validationKey 특성 설정

웹 팜에서 각 클라이언트 요청은 모든 포스트백에서 다른 컴퓨터로 이동될 수 있습니다. 이 동작으로 인해 특성을 Machine.config 파일에서 로 설정할 AutoGenerate 수 없습니다validationKey. 대신 특성 값을 웹 팜의 validationKey 모든 컴퓨터에서 공유하는 고정 문자열로 설정해야 합니다.

동적으로 생성된 형식을 웹 팜의 viewstate에 저장하지 마세요.

ASP.NET 파일을 동적으로 컴파일하면 파일이 임의 이름을 가진 어셈블리에 기본 제공됩니다(예: 파일 이름은 jp395dun.dll수 있음). 웹 팜을 실행하는 경우 동일한 파일이 서로 다른 임의 이름을 가진 어셈블리로 컴파일됩니다. 일반적으로 이러한 어셈블리 이름을 가정하는 사람은 아무도 없기 때문에 문제가 되지 않습니다. 그러나 이진 serialization을 사용하여 동적으로 컴파일된 형식을 viewstate에 배치한 경우 어셈블리 이름은 viewstate 데이터의 일부로 포함됩니다. 나중에 해당 viewstate가 웹 팜의 다른 서버로 전송되면 뷰스테이트는 다른 어셈블리 이름을 사용하므로 역직렬화할 수 없습니다.

최상의 해결 방법은 이진 serialization을 사용하지 않는 것입니다. 이진 serialization은 이 문제가 발생하지 않는 경우에도 많은 리소스를 사용합니다. 대신 viewstate에 배치한 항목을 배열, 쌍, 삼중값 및 단순 형식(예: 문자열, int 및 기타 형식)의 조합으로 제한합니다. System.Web.UI.PairSystem.Web.UI.Triplet 는 뷰스테이트 엔진이 효율적으로 처리할 수 있는 간단한 래퍼 형식입니다.

이 문제를 방지하기 위한 또 다른 해결 방법은 viewstate에 저장하는 형식을 폴더 또는 Global Assembly 캐시의 미리 컴파일된 어셈블리 Bin 로 이동하는 것입니다. 이 수정은 성능을 다루지 않지만 어셈블리가 모든 컴퓨터에서 동일한 이름을 갖습니다.

참고

viewstate에 복잡한 데이터 형식을 저장하고 이 문제가 발생하는 경우 호출 스택 정보에는 다음과 유사한 스택이 포함됩니다.

[FileNotFoundException: Could not load file or assembly 'App_Web_fx--sar9, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.]
 System.RuntimeTypeHandle._GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark, Boolean loadTypeFromPartialName) +0
System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark) +72
System.RuntimeType.PrivateGetType(String typeName, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark) +58
System.Type.GetType(String typeName, Boolean throwOnError) +57
System.Web.UI.ObjectStateFormatter.DeserializeType(SerializerBinaryReader reader) +192 
System.Web.UI.ObjectStateFormatter.DeserializeValue(SerializerBinaryReader reader) +943 
System.Web.UI.ObjectStateFormatter.DeserializeValue(SerializerBinaryReader reader) +384 
System.Web.UI.ObjectStateFormatter.DeserializeValue(SerializerBinaryReader reader) +198 
System.Web.UI.ObjectStateFormatter.DeserializeValue(SerializerBinaryReader reader) +210 
System.Web.UI.ObjectStateFormatter.DeserializeValue(SerializerBinaryReader reader) +198 
System.Web.UI.ObjectStateFormatter.Deserialize(Stream inputStream) +142

MAC(viewstate Machine Authentication Code) 기능의 목적은 클라이언트가 악의적인 viewstate가 포함된 요청을 보낼 수 없도록 하는 것입니다. 기본적으로 이 기능은 Machine.config 파일의 다음 플래그에서 사용하도록 설정됩니다.

enableViewStateMac="true"

처리하는 문제가 MAC 기능과 관련이 있는지 여부를 확인하는 가장 간단한 방법은 기능을 끄는 것입니다. 이렇게 하려면 Machine.config 파일의 플래그를 다음 코드로 변경합니다.

enableViewStateMac="false"

viewstate 오류가 더 이상 발생하지 않으면 문제가 MAC 기능과 관련이 있습니다.

중요

문제를 진단하는 데 도움이 되도록 viewstate MAC 기능만 끕니다. 이 문제를 해결하기 위해 viewstate MAC이 꺼져 있으면 안 됩니다. 이렇게 하면 보안 허점을 도입할 수 있습니다. 자세한 내용은 보안 ASP.NET 애플리케이션 빌드: 인증, 권한 부여 및 보안 통신을 참조하세요.

viewstate MAC 기능을 끈 다음 HTML 인코딩하지 않는 컨트롤(예: 레이블 컨트롤)에 viewstate를 사용하는 경우 공격자는 viewstate 데이터를 변조하고 임의의 데이터를 viewstate에 배치할 수 있습니다. 이 임의 데이터는 디코딩된 다음 게시된 페이지를 렌더링할 때 컨트롤에서 사용됩니다. 따라서 공격을 방지하기 위해 노력하지 않는 한 공격자는 애플리케이션에 스크립트를 삽입할 수 있습니다. 예를 들어 공격자는 데이터를 디코딩하고 레이블 컨트롤이 있는 데이터에 스크립트를 삽입한 다음 웹 사이트에서 연결할 수 있습니다. 링크를 클릭하는 사람은 잠재적으로 인증 쿠키 또는 세션 ID를 도용할 수 있는 스크립트 삽입 공격의 희생자가 됩니다. 또한 이 스크립트를 사용하면 공격자가 viewstate 및 애플리케이션별 공격을 사용하는 컨트롤에 대한 상태 데이터를 변경할 수 있습니다.

일반적으로 출력(예: DataGrid 컨트롤, DataList 컨트롤, 레이블 컨트롤 및 기타 컨트롤)을 HTML로 인코딩하지 않는 모든 컨트롤에 대해 viewstate를 사용하지 않도록 설정했거나 각 요청에 대한 값을 항상 안전한 것으로 알려진 값으로 명시적으로 설정한다고 확신하지 않는 한 보기 상태 MAC 기능을 해제하지 않는 것이 좋습니다.

오류 메시지를 받을 때 발생하는 예외를 정확히 확인합니다.

아쉽게도 이 문서의 소개 섹션에 언급된 잘못된 viewstate 오류 메시지는 정보를 제공하는 것이 아닙니다. 오류 메시지는 viewstate가 처리될 때 일부 예외가 생성되어 발생합니다. 문제는 예외가 사용되고 있으며 오류 메시지에서 세부 정보가 손실된다는 것입니다.

디버거를 사용하여 원래 예외를 확인할 수 있습니다. 이렇게 하려면 디버거를 ASP.NET 프로세스(Aspnet_wp.exe 또는 W3wp.exe)에 연결한 다음 모든 예외를 catch하도록 설정해야 합니다. 디버거는 관련이 없는 몇 가지 예외에서 중지될 수 있지만 결국 viewstate 예외에 도달하고 문제 해결에 유용한 정보를 제공합니다.

다음 단계는 런타임 디버거(Cordbg.exe)를 사용하는 예제입니다.

  1. 명령 프롬프트에서 명령을 실행 iisreset 하여 좋은 시작점이 제공되었는지 확인한 다음 사이트의 페이지로 이동합니다.

  2. cordbg.exe을(를) 실행합니다.

  3. 를 입력 <pro>한 다음 Enter 키를 누릅니 . 관리되는 프로세스 목록이 표시됩니다. Aspnet_wp.exe 또는 W3wp.exe 프로세스가 표시됩니다. 해당 PID에 유의하세요.

  4. 를 입력합니다 <PID>.

    참고

    PID를 3단계에서 기록한 PID로 바꿉다.

  5. ca e를 입력하여 Cordbg.exe 모든 예외를 중단하도록 지시한 다음, 프로세스를 실행합니다<gto>.

  6. 예외가 발생할 때마다 를 입력 <w> 하여 스택을 확인합니다. 스택이 viewstate 예외인 경우(스택에서 찾습니다 LoadPageStateFromPersistenceMedium ) 명령 창에서 모든 예외 및 스택 정보를 복사한 다음 정보를 저장합니다. 이 정보는 문제를 이해하는 데 도움이 될 수 있습니다. 예외가 관련이 없는 경우 를 입력합니다 <g>.

세션에 viewstate를 저장해 보세요.

기본적으로 viewstate는 브라우저로 전송되는 필드로 <input type=hidden> 라운드트립됩니다. 그런 다음 브라우저는 다음 요청에서 필드를 서버로 다시 보냅니다. 경우에 따라 이 뷰스테이트는 커질 수 있으며 잠재적인 문제의 원천이 될 수 있습니다. 일부 브라우저는 이러한 큰 숨겨진 필드(및 결과 큰 요청)를 처리할 수 없으며 브라우저가 viewstate를 잘라낼 수 있습니다. viewstate를 잘면 "viewstate가 손상됨" 오류 메시지가 발생합니다. 이 동작은 더 간단한 브라우저에서 발생할 가능성이 높습니다. 예를 들어 이 동작은 PDA의 브라우저에서 발생할 수 있습니다.

이러한 문제가 발생할 수 있는지 여부를 확인하려면 세션에 viewstate를 저장해 보세요. 다음 예제에서는 이 작업을 수행하는 방법을 보여 줍니다.

<%@ language=c# debug=true %> 

<script runat=server> 
protected override object LoadPageStateFromPersistenceMedium() 
{ 
    return Session["_ViewState"]; 
}

protected override void SavePageStateToPersistenceMedium(object viewState) 
{ 
    Session["_ViewState"] = viewState; 
}

void TextChanged(object o, EventArgs e) 
{ 
    Response.Write("TextChanged"); 
} 
</script> 
<form runat=server> 
<asp:button text=Test runat=server/> 
<asp:textbox ontextchanged=TextChanged runat=server/> 
<input type=hidden name=__VIEWSTATE> 
</form> 

작업자 프로세스 재활용으로 인해 문제가 발생하는지 확인

다음 시나리오를 고려하세요.

  • MICROSOFT 인터넷 정보 서비스(IIS) 6.0에서 ASP.NET 실행하고 있습니다.
  • 애플리케이션 풀은 로컬 시스템 계정, 네트워크 서비스 계정 또는 관리 수준 계정이 아닌 ID로 실행됩니다.
  • validationKey 요소의 <machineKey> 특성은 구성 파일에서 로 설정 AutoGenerate 됩니다.

이 시나리오에서는 다음 절차를 수행하면 viewstate 오류가 발생합니다.

  1. 사용자가 페이지를 찾습니다.
  2. ASP.NET 애플리케이션을 재활용하는 작업자 프로세스입니다.
  3. 사용자가 페이지를 다시 게시합니다.

이 시나리오에 대한 해결 방법으로 구성 파일에서 명시적 validationKey 특성을 사용합니다.

참조