이 문서에서는 Microsoft ASP.NET 애플리케이션의 viewstate 문제를 디버깅하고 해결하는 기술을 소개합니다.
원래 제품 버전: ASP.NET
원래 KB 번호: 829743
소개
Viewstate는 서버 상태(예: 세션 상태)를 사용하지 않고 페이지가 자동으로 상태를 유지할 수 있도록 하는 ASP.NET 기능입니다. 그러나 viewstate와 관련된 문제는 디버그하기 어려울 수 있습니다. 대부분의 경우 viewstate에 문제가 발생하면 웹 브라우저에서 다음과 같은 오류 메시지가 표시되고 문제의 원인이 무엇인지 거의 알 수 없습니다.
viewstate가 이 페이지에 유효하지 않으며 손상되었을 수 있습니다.
이 문서에서는 디버깅 및 viewstate 문제 해결에 사용할 수 있는 몇 가지 기술에 대해 설명합니다.
웹 팜에서 실행 중인 경우 validationKey 특성 설정
웹 팜에서 각 클라이언트 요청은 모든 포스트백에서 다른 컴퓨터로 갈 수 있습니다. 이러한 동작 때문에 validationKey 특성을 Machine.config 파일에서 AutoGenerate로 설정된 상태로 둘 수 없습니다. 대신 특성 값을 웹 팜의 validationKey 모든 컴퓨터에서 공유하는 고정 문자열로 설정해야 합니다.
동적으로 생성된 형식을 웹 팜의 viewstate에 저장하지 마세요.
ASP.NET 파일을 동적으로 컴파일하는 경우 임의 이름을 가진 어셈블리에 파일이 기본 제공됩니다(예: 파일 이름은 jp395dun.dll수 있습니다). 웹 팜을 실행하는 경우 동일한 파일이 서로 다른 임의 이름을 가진 어셈블리로 컴파일됩니다. 일반적으로 해당 어셈블리 이름을 가정하는 사람은 아무도 없기 때문에 문제가 되지 않습니다. 그러나 이진 직렬화를 사용하여 동적으로 컴파일된 형식을 ViewState에 배치하면 어셈블리 이름이 ViewState 데이터의 일부로 포함됩니다. 나중에 해당 viewstate가 웹 팜의 다른 서버로 전송되면 뷰스테이트는 다른 어셈블리 이름을 사용하므로 역직렬화할 수 없습니다.
최상의 해결 방법은 이진 serialization을 사용하지 않는 것입니다. 이진 serialization은 이 문제가 발생하지 않는 경우에도 많은 리소스를 사용합니다. 대신 viewstate에 배치한 항목을 배열, 쌍, 삼중자 및 단순 형식(예: 문자열, int 및 기타 형식)의 조합으로 제한합니다.
System.Web.UI.Pair 뷰 System.Web.UI.Triplet 스테이트 엔진이 효율적으로 처리할 수 있는 간단한 래퍼 형식입니다.
이 문제를 방지하기 위한 다른 해결 방법은 viewstate에 저장하는 형식을 폴더 또는 Bin 캐시의 미리 컴파일된 어셈블리 Global Assembly 로 이동하는 것입니다. 이 수정은 성능을 다루지 않지만 모든 컴퓨터에서 어셈블리의 이름이 같을 수 있습니다.
참고 항목
복잡한 데이터 형식을 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
문제가 viewstate MAC 기능과 관련되어 있는지 확인
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에 배치할 수 있습니다. 이 임의 데이터는 디코딩된 다음 게시된 페이지를 렌더링할 때 컨트롤에서 사용됩니다. 따라서 공격을 방지하기 위해 노력하지 않는 한 공격자는 애플리케이션에 스크립트를 삽입할 수 있습니다. 예를 들어 공격자는 데이터를 디코딩하고 레이블 컨트롤이 있는 데이터에 스크립트를 삽입한 다음 웹 사이트에서 연결할 수 있습니다. 링크를 선택하는 사람은 인증 쿠키 또는 세션 ID를 도용할 수 있는 스크립트 삽입 공격의 희생자가 될 수 있습니다. 또한 이 스크립트를 사용하면 공격자가 viewstate를 사용하는 컨트롤에 대한 상태 데이터를 변경하고 결과적으로 애플리케이션 관련 공격이 발생할 수 있습니다.
일반적으로 출력(예: DataGrid 컨트롤, DataList 컨트롤, 레이블 컨트롤 및 기타 컨트롤)을 HTML로 인코딩하지 않는 모든 컨트롤에 대해 viewstate를 사용하지 않도록 설정했거나 각 요청에 대한 값을 안전한 것으로 알려진 값으로 항상 명시적으로 설정한다고 확신하지 않는 한 보기 상태 MAC 기능을 해제하지 않는 것이 좋습니다.
오류 메시지를 받을 때 발생하는 예외를 정확히 확인합니다.
아쉽게도 이 문서의 소개 섹션에 있는 잘못된 viewstate 오류 메시지는 유익하지 않습니다. 오류 메시지는 viewstate가 처리될 때 생성되는 일부 예외로 인해 발생합니다. 문제는 예외가 사용되고 있으며 오류 메시지에서 세부 정보가 손실된다는 것입니다.
디버거를 사용하여 원래 예외를 확인할 수 있습니다. 이렇게 하려면 ASP.NET 프로세스(Aspnet_wp.exe또는 W3wp.exe)에 디버거를 연결한 다음 모든 예외를 catch하도록 설정해야 합니다. 디버거는 관련이 없는 몇 가지 예외에서 중지되지만 결국에는 viewstate 예외에 도달하고 문제 해결에 유용한 정보를 제공합니다.
다음 단계는 런타임 디버거(Cordbg.exe)를 사용하는 예제입니다.
명령 프롬프트에서 명령을 실행
iisreset하여 좋은 시작점이 제공되었는지 확인한 다음 사이트의 페이지로 이동합니다.cordbg.exe를 실행합니다.<pro>을 입력한 다음 Enter 키를 누릅니다. 관리되는 프로세스 목록이 표시됩니다. Aspnet_wp.exe 또는 W3wp.exe 프로세스가 표시됩니다. 해당 PID에 유의하세요.를 입력합니다
<PID>.참고 항목
PID를 3단계에서 적어 두는 PID로 바꿉다.
ca e를 입력하여 Cordbg.exe 모든 예외를 중단하도록 지시한 다음 프로세스를 실행합니다
<gto>.예외가 발생할 때마다 스택을 보려면 입력
<w>합니다. 스택이 viewstate 예외인 경우(스택에서 찾음LoadPageStateFromPersistenceMedium) 명령 창에서 모든 예외 및 스택 정보를 복사한 다음 정보를 저장합니다. 이 정보는 문제를 이해하는 데 도움이 될 수 있습니다. 예외가 관련이 없는 경우 .를 입력합니다<g>.
세션에 viewstate를 저장해 보세요.
기본적으로 viewstate는 브라우저로 전송되는 필드와 함께 <input type=hidden> 라운드트립됩니다. 그런 다음 브라우저는 다음 요청에서 해당 필드를 서버로 다시 보냅니다. 경우에 따라 이 뷰스테이트는 커질 수 있으며 잠재적인 문제의 원인일 수 있습니다. 일부 브라우저는 이러한 큰 숨겨진 필드(및 결과 큰 요청)를 처리할 수 없으며 브라우저에서 viewstate를 잘라낼 수 있습니다. viewstate를 잘면 "viewstate corrupted" 오류 메시지가 발생합니다. 이 동작은 더 간단한 브라우저에서 발생할 가능성이 높습니다. 예를 들어 이 동작은 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 오류가 발생합니다.
- 사용자가 페이지를 찾습니다.
- ASP.NET 애플리케이션을 재활용하는 작업자 프로세스입니다.
- 사용자가 페이지를 다시 게시합니다.
이 시나리오에 대한 해결 방법으로 구성 파일에서 명시적 validationKey 특성을 사용합니다.