ASP.NET ビューステートの概要
更新 : 2007 年 11 月
ASP.NET Page Framework で使用されるビューステートは、ページとコントロールの値をラウンド トリップ間で保持する方法です。ページの HTML マークアップを表示するときに、ポストバック間で保持する必要のある現在のページの状態と値を Base64 でエンコードした文字列にシリアル化します。次に、この情報がビューステートの隠しフィールドに出力されます。
このトピックの内容は次のとおりです。
シナリオ
ViewState の機能
背景
クラス リファレンス
その他のリソース
新機能
シナリオ
ビューステートは、ポストバック間で維持する必要がある情報を保持するために、ASP.NET Page Framework で自動的に使用されます。この情報には、コントロールの既定値以外の値が含まれます。
ビューステートを使用して、ページに固有のアプリケーション データを格納することもできます。
ページのトップへ
機能
ビューステートは、ポストバック時に保持する必要のある値を格納できる、ASP.NET ページ内のリポジトリです。ページ フレームワークはビューステートを使用して、ポストバック間でコントロール設定を維持します。
独自のアプリケーションでビューステートを使用すると、次の操作を実行できます。
セッション状態またはユーザー プロファイルに値を格納することなくポストバック間で値を保持します。
ユーザーが定義するページ プロパティまたはコントロール プロパティの値を格納します。
SQL Server データベースまたは別のデータ ストアにビューステート情報を格納できる、カスタム ビューステート プロバイダを作成します。
たとえば、ページ読み込みイベントで次回ページをサーバーに送信するときにコードがアクセスする情報をビューステートに格納できます。使用上の推奨事項については、「ASP.NET の状態管理に関する推奨事項」を参照してください。
ページのトップへ
背景
Web アプリケーションには状態がありません。サーバーからページを要求されるたびに Web ページ クラスの新しいインスタンスが作成されます。これは、通常、1 回のラウンド トリップごとにページとそのコントロールですべての情報が失われることを意味します。たとえば、既定では、ユーザーが HTML Web ページのテキスト ボックスに情報を入力すると、その情報はサーバーに送信されます。しかし、その情報は応答でブラウザに返送されません。
Web プログラミング固有のこの制限に対処するために、ASP.NET Page Framework には、Web サーバーへのラウンド トリップ間でページとコントロールの値を保持するための状態管理機能がいくつか用意されています。この機能の 1 つがビューステートです (ASP.NET の状態管理の概要)。
既定では、ASP.NET Page Framework は、ビューステートを使用して、ページとコントロールの値をラウンド トリップ間で保持します。ページの HTML を表示するときに、ポストバック間で保持する必要のある現在のページの状態と値を Base64 でエンコードした文字列にシリアル化します。次に、この情報がページの隠しフィールドに出力されます。
ページの ViewState プロパティを使用して、コード内のビューステートにアクセスできます。ViewState プロパティは、ビューステート データを含むキーと値のペアが格納されたディクショナリです。
セキュリティに関するメモ : |
---|
悪意のあるユーザーにとっては、隠しフィールドの内容を見たり変更したりするのは簡単なことです。ビューステート データを保護する方法の詳細については、このトピックの「ビューステートのセキュリティ保護」を参照してください。 |
ビューステートに情報を格納するときの推奨事項については、「ASP.NET の状態管理に関する推奨事項」を参照してください。
ページのデータを格納するカスタムの PageStatePersister クラスを実装すると、既定の動作を変更して別の場所にある SQL Server データベースなどにビューステートを格納できます。非表示フィールドではなくストリームにページ状態を格納する方法の例については、PageStatePersister クラスの例を参照してください。
ビューステートの使用に関する考慮事項
ビューステートが提供する状態情報は、特定の ASP.NET ページに関するものです。複数のページの情報を使用する必要がある場合や、Web サイトへの訪問以外の目的で情報を保持する必要がある場合は、別の方法で状態を維持する必要があります。アプリケーション状態、セッション状態、またはプロファイル プロパティを使用できます。
ビューステート情報は XML にシリアル化された後で Base64 エンコーディングを使用してエンコードされます。このため、大量のデータが生成される可能性があります。ページをサーバーにポストすると、ビューステートの内容がページのポストバック情報の一部として送信されます。ビューステートに大量の情報が格納されている場合、ページのパフォーマンスに影響を与える可能性があります。アプリケーションの通常のデータを使用してページのパフォーマンスをテストし、ビューステートのサイズがパフォーマンス上の問題を発生させるかどうかを確認します。ビューステートの代わりとして使用する手段については、「ASP.NET の状態管理に関する推奨事項」を参照してください。
個別のコントロールのコントロール情報を格納する必要がない場合は、コントロールのビューステートを無効にできます。各ポストバックのデータ ストアからページのコントロールが更新される場合、ビューステートのサイズを小さくするために、そのコントロールのビューステートをオフにできます。たとえば、GridView コントロールなどのコントロールのビューステートをオフにできます。
メモ : |
---|
ビューステートを明示的にオフにした場合でも、隠しフィールドは引き続きブラウザに送信されて、ページのポストバックが発生していることを示します。 |
そのほかに、隠しフィールドに格納するデータが大量になると、プロキシやファイアウォールによってはデータを含むページにアクセスできなくなる場合があることに注意する必要があります。許可されるデータの最大量はファイアウォール実装やプロキシ実装によって異なるため、サイズの大きい隠しフィールドを使用すると断続的な問題が発生する可能性があります。ViewState プロパティに格納されているデータの容量がページの MaxPageStateFieldLength プロパティで指定されている値を超えると、ページはビューステートを複数の隠しフィールドに分割します。これにより、ファイアウォールが拒否するサイズを下回るように個々の隠しフィールドのサイズが小さくなります。
一部のモバイル デバイスは、隠しフィールドをまったく使用できません。このため、これらのデバイスではビューステートは機能しません。詳細と代替策については、「ASP.NET モバイル Web 開発の概要」を参照してください。
コントロールの状態
ビューステート以外に、ASP.NET はコントロールの状態をサポートしています。ページまたはコントロールに対してビューステートが無効の場合でも、ページはコントロールの状態を使用して、ポストバックの間維持する必要のあるコントロール情報を保持します。ビューステートと同様に、コントロールの状態は 1 つ以上の隠しフィールドに格納されます。
ビューステートへの値の保存
ディクショナリ オブジェクトを公開するページの ViewState プロパティを使用することにより、ビューステート情報にアクセスできます。このディクショナリを使用してカスタム値を格納できます。一般的な使用法としては、ページで定義したカスタム プロパティの値を格納します。
ビューステートは隠しフィールドとして送信されるため、ページの PreRenderComplete イベントが発生するまでビューステートを変更できます。ブラウザにページが表示されると、ビューステートに対する変更は保存されません。
Web ページのソースを表示し、Base64 エンコードされた文字列をデコードできる場合は、隠しビューステート フィールド内の情報を確認することができます。これにより、セキュリティ上の問題が発生する場合があります。ビューステートのセキュリティ上の問題の詳細については、このトピックの「ビューステートのセキュリティ保護」を参照してください。
メモ : |
---|
ViewState プロパティを使用するには、ASP.NET Web ページに runat="server" 属性を持つ form 要素が含まれている必要があります。 |
値をビューステートに保存するには、保存する値を含む新しい項目を作成し、その項目をビューステート ディクショナリに追加します。文字列と整数値をビューステートに保存するコードを含む ASP.NET Web ページの例を次に示します。
<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
' Sample ArrayList for the page.
Dim PageArrayList As ArrayList
Function CreateArray() As ArrayList
' Create a sample ArrayList.
Dim result As ArrayList
result = New ArrayList(4)
result.Add("item 1")
result.Add("item 2")
result.Add("item 3")
result.Add("item 4")
Return result
End Function
Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
If (Me.ViewState("arrayListInViewState") IsNot Nothing) Then
PageArrayList = CType(Me.ViewState("arrayListInViewState"), ArrayList)
Else
' ArrayList isn't in view state, so it must be created and populated.
PageArrayList = CreateArray()
End If
' Code that uses PageArrayList.
End Sub
Sub Page_PreRender(ByVal sender As Object, ByVal e As EventArgs)
' Save PageArrayList before the page is rendered.
Me.ViewState.Add("arrayListInViewState", PageArrayList)
End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>View state sample</title>
</head>
<body>
<form id="form1" runat="server">
<div>
</div>
</form>
</body>
</html>
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
// Sample ArrayList for the page.
ArrayList PageArrayList;
ArrayList CreateArray()
{
// Create a sample ArrayList.
ArrayList result = new ArrayList(4);
result.Add("item 1");
result.Add("item 2");
result.Add("item 3");
result.Add("item 4");
return result;
}
void Page_Load(object sender, EventArgs e)
{
if (ViewState["arrayListInViewState"] != null)
{
PageArrayList = (ArrayList)ViewState["arrayListInViewState"];
}
else
{
// ArrayList isn't in view state, so it must be created and populated.
PageArrayList = CreateArray();
}
// Code that uses PageArrayList.
}
void Page_PreRender(object sender, EventArgs e)
{
// Save PageArrayList before the page is rendered.
ViewState.Add("arrayListInViewState", PageArrayList);
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>View state sample</title>
</head>
<body>
<form id="form1" runat="server">
<div>
</div>
</form>
</body>
</html>
ビューステートに格納できるデータ型
ビューステートに格納できるオブジェクトの型は次のとおりです。
文字列 (String)
整数 (Integer)
Boolean 値
Array オブジェクト
ArrayList オブジェクト
ハッシュ テーブル
カスタムの型コンバータ (詳細については、TypeConverter クラスを参照してください)
他の型のデータも格納できますが、ビューステートがその値をシリアル化できるように、Serializable 属性でクラスをコンパイルする必要があります。
ビューステートからの値の読み取り
ビューステートから値を読み取るには、ページの ViewState プロパティを取得し、ビューステート ディクショナリからその値を読み取ります。
ビューステートから arrayListInViewState という名前の ArrayList オブジェクトを取得し、GridView コントロールをデータ ソースとしてオブジェクトにバインドする方法の例を次に示します。
Dim arrayList As ArrayList
arrayList = CType(ViewState("arrayListInViewState"), ArrayList)
Me.GridView1.DataSource = arrayList
Me.GridView1.DataBind()
arrayList = new ArrayList();
arrayList = (ArrayList)ViewState["arrayListInViewState"];
this.GridView1.DataSource = arrayList;
this.GridView1.DataBind();
ビューステートの値は String 型として型指定されます。Visual Basic で Option Strict On を設定する場合、前の例で示したように、ビューステート値は、適切な型にキャストしてから使用する必要があります。C# では、ビューステート値を読み取るときは常に適切な型にキャストする必要があります。
ビューステートから存在しない値を取得しようとしても、例外はスローされません。値がビューステートにあることを確認するには、まずオブジェクトが存在するかどうかを確認します。ビューステート エントリを確認する方法の例を次に示します。
If ViewState("color") Is Nothing Then
' No such value in view state, take appropriate action.
End If
if (ViewState["color"] == null)
// No such value in view state, take appropriate action.
たとえば、型を調べるためなどの目的で、存在しないビューステート エントリを他の方法で使用しようとした場合、NullReferenceException 例外がスローされます。
ページのトップへ
ビューステートのセキュリティ保護
既定では、ビューステート データは、ページの隠しフィールドに格納され、Base-64 エンコーディングを使用してエンコードされます。また、ビューステート データのハッシュは、MAC (Machine Authentication Code) キーを使用してデータから作成されます。ハッシュ値がエンコードされたビューステートに追加され、この文字列がページに格納されます。ページがサーバーにポストバックされると、ASP.NET ページ フレームワークはハッシュ値を再計算し、そのハッシュ値と、ビューステートに格納されている値を比較します。ハッシュ値が一致しない場合、例外が発生し、ビューステート データが無効である可能性が示されます。
ハッシュ値を作成することで、ASP.NET ページ フレームワークは、ビューステート データが破損または改ざんされていないかどうかをテストできます。ただし、改ざんされていない場合でも、ビューステート データは悪意のあるユーザーによって傍受され、読み取られる可能性があります。
ビューステート ハッシュ値を計算するための MAC の使用
ビューステート ハッシュ値の計算に使用される MAC キーは、自動生成されるか、Machine.config ファイルで指定されます。キーが自動生成される場合、コンピュータの MAC アドレスに基づいて作成されます。MAC アドレスは、そのコンピュータにインストールされているネットワーク アダプタの一意の GUID 値です。
悪意のあるユーザーが、ビューステートのハッシュ値に基づいて MAC キーをリバース エンジニアリングするのは困難です。したがって、MAC エンコーディングは、ビューステート データが変更されていないかどうかを確認するための適度に信頼性の高い方法と言えます。
通常、ハッシュの生成に使用する MAC キーが大きいほど、異なる文字列のハッシュ値が同じになる確率は低くなります。キーを自動生成する場合、ASP.NET は SHA-1 エンコーディングを使用して大型のキーを作成します。ただし、Web ファーム環境では、すべてのサーバーで同一の MAC キーを使用する必要があります。MAC キーが同一でないときに、ページを作成したサーバーとは別のサーバーにページがポストバックされると、ASP.NET ページ フレームワークは例外を発生します。そのため、Web ファーム環境では、ASP.NET がキーを自動生成できるようにするのではなく、Machine.config ファイルでキーを指定する必要があります。その場合は、ハッシュ値に十分なセキュリティを提供できる長さのキーを作成するようにします。ただし、キーが長くなればなるほど、ハッシュの作成にかかる時間も長くなります。そのため、セキュリティ上のニーズとパフォーマンス上のニーズを比較検討する必要があります。
ビューステートの暗号化
MAC エンコーディングは、ビューステート データの改ざんを防止するうえでは役立ちますが、ユーザーによるデータの参照は防止できません。このデータは、2 とおりの方法でユーザーが参照できないようにできます。1 つは、ページを SSL 経由で送信する方法で、もう 1 つは、ビューステート データを暗号化する方法です。ページが SSL 経由で送信されるようにすると、データ パケットの盗聴や、ページが対象としていないユーザーによる不正なデータ アクセスを防止できます。
ただし、SSL はページをブラウザに表示するためにページを復号化するため、ページを要求したユーザーは、ビューステート データを参照できます。これは、ビューステート データにアクセスできる承認済みユーザーについては心配する必要がない場合には問題ありません。ただし、どのユーザーにもアクセスを許可できないような情報をビューステートに格納するようなコントロールもあります。たとえば、ビューステート内にアイテム ID (データ キー) を格納するデータ バインド コントロールがページに含まれている場合です。これらの ID に、顧客 ID などの重要情報が含まれている場合は、SSL 経由でページを送信するだけでなく、または SSL 経由でページを送信する代わりに、ビューステート データを暗号化する必要があります。
ビューステート データを暗号化するには、ページの ViewStateEncryptionMode プロパティに true を設定します。情報をビュー ステートに格納すると、通常の読み取りおよび書き込み方法を利用でき、暗号化と復号化がページによってすべて処理されます。ビューステート データを暗号化すると、アプリケーションのパフォーマンスに影響する可能性があります。そのため、暗号化は必要な場合以外には使用しないでください。
コントロールの状態の暗号化
コントロールの状態を使用するコントロールには、RegisterRequiresViewStateEncryption メソッドを呼び出して、ビューステートを暗号化する必要があるものもあります。ページのコントロールがビューステートの暗号化を必要とする場合、ページのすべてのビューステートが暗号化されます。
ユーザーごとのビューステートのエンコーディング
Web サイトがユーザーを認証する場合、Page_Init イベント ハンドラに ViewStateUserKey プロパティを設定して、ページのビューステートを特定のユーザーと関連付けることができます。これはワン クリック攻撃の防止に役立ちます。この攻撃では、悪意のあるユーザーが、以前作成したページからあらかじめビューステートが埋め込まれている有効な Web ページを作成します。攻撃者は、ユーザーに、ユーザー ID を使用してサーバーにページを送信するリンクをクリックするように促します。
ViewStateUserKey プロパティが設定されていると、元のページのビューステートのハッシュを作成するのに攻撃者の ID が使用されます。何も知らないユーザーがページを再送信してしまった場合でも、ユーザー キーが異なるのでハッシュ値が異なります。ページは検証に失敗し、例外がスローされます。
ViewStateUserKey プロパティを、各ユーザーに対して一意の値 (ユーザー名やユーザー ID など) に関連付ける必要があります。
共有ホスト環境での構成のセキュリティ保護
共有ホスト環境では、状態管理プロパティが悪意のあるユーザーによって変更される可能性があり、コンピュータ上の他のアプリケーションに影響する場合があります。このような変更は、Machine.config ファイルを直接変更したり、構成クラスを介して変更したり、その他の管理ツールや構成ツールを使用したりして行われる可能性があります。アプリケーション構成の変更は、構成ファイルのセクションを暗号化することによって防止できます。詳細については、「保護された構成を使用した構成情報の暗号化」を参照してください。
クラス リファレンス
同じページに対する要求間で値を保持するためのディクショナリ オブジェクトを提供します。 |
|
SQL Server データベースなどにビューステート情報を保存するためのカスタム機構を定義する手段を提供します。 |
ページのトップへ
参照
概念
参照
ページのトップへ