by WebSurfer
2011年8月19日 20:34
MSDN ライブラリの ASP.NET の組み込み機能を活用し、Web 攻撃を回避する で、ワンクリック攻撃を防ぐために、Page.ViewStateUserKey プロパティにセッション ID を設定することを推奨しています。
その場合、セッションが timeout(デフォルトで 20 分)すると ViewState の検証結果はどうなるでしょうか?
EnableViewStateMac が有効に設定してある場合(デフォルトで有効になっています)例外がスローされると思っていましたが、そうではなかったです。
timeout するとサーバーに保存されていたセッションデータは破棄されますが、セッション ID は書き換えられず、同じ ID が使用され続けます。即ち、Session["xxxxx"] に保存したデータは破棄されても、ブラウザとサーバ間のセッションは維持されるということのようです。
という訳で、ViewStateUserKey をセッション ID に設定してセッションが timeout しても、ViewState の検証結果は有効になります。
ちなみに、セッション ID が再発行されるのは、regenerateExpiredSessionId が有効で、かつ、cookieless モードが ture の場合のみだそうです。
知ってました? 自分は知らなかったです。(笑)
参考に、検証に使ったコードをアップしておきます。sessionState 要素の timeout 属性を短く設定して検証してみました。
<%@ 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">
// timeout するとサーバーのメモリにあるデータは破棄されるが、
// SessionID は書き換えらえず、同じ ID が使用され続ける。
// 既定では、セッション ID は regenerateExpiredSessionId が
// 有効な場合に cookieless モードに対してのみ再発行される。
// したがって、timeout しても ViewState は有効。
protected void Page_Init(object sender, EventArgs e)
{
ViewStateUserKey = Session.SessionID;
}
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
Session["message"] =
"この文字列はセッションから取得しました。";
}
else
{
object obj = Session["message"];
if (obj != null)
{
Label1.Text = (string)obj;
}
else
{
Label1.Text = "セッションが null です。";
}
}
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Button ID="Button1" runat="server" Text="Button" />
<asp:Label ID="Label1" runat="server"></asp:Label>
</div>
</form>
</body>
</html>
-------- 2012/2/6 追記 --------
SessionState 情報を格納しない場合(Session["Data"] = xxxx; というようなコードが存在しない場合)、サーバーは SessionState 情報用のストレージを割り当てません。また、セッション Cookie も発行しません。(2014/7/26 追記:Global.asax に Session_Start ハンドラを追加すると話が違ってきます。詳しくは、Session_Start ハンドラの影響 を参照ください)
SessionID は SessionStateModule が生成しますが、Cookie が送られてこなければ SessionStateModule が生成する SessionID の値はリクエストのたび異なります。
なので、ViewStateUserKey = Session.SessionID; とすることにより、サーバーエラーになります。エラーメッセージは以下の通りです。
"System.Web.HttpException: viewstate MAC の検証フィールドです。このアプリケーションが Web Farm またはクラスタによってホストされている場合、<machineKey> 構成が同一の validationKey および検証アルゴリズムを指定していることを確認してください。AutoGenerate をクラスタで使用することはできません。"