none
ビューステートとセッションによる遷移の検証の問題 RRS feed

  • 質問

  • ASP.NETによるWebアプリケーションでビューステートとセッションでページ遷移の検証を行っているもので、

    http://www.vbforums.com/showthread.php?t=588685

    と類似のケースなんですが、

    Chromeでのみ検証に失敗するケースに遭遇しているのですが、これの原因がよくわからず困っています。
    ご教授いただければ幸いです。

    2012年6月6日 3:56

回答

  • サーバー側での話しなので、ブラウザは関係ないと思いますが、間違いなく以下のコー
    ドで Chrome 以外では取得できたのでしょうか?

    > object clientToken = this.PreviousPage.Items[TOKEN_KEY];

    自分が試した環境(ASP.NET 4, IIS7, Vista SP2, VS2010 Pro)では、Chrome に限らず、
    主要なブラウザの最新版 IE9, Firefox 13.0, Chrome 19.0.1084.52, Safari 5.1.7,
    Opera 11.64 すべて同じく取得できませんでしたけど(結果は null になる)。

    以下のページの「メモ」に書いてあるように、"ソース ページの隠しフィールドに値を
    文字列として格納し、ターゲット ページの Request.Form を使用してアクセスします。"
    としてはいかがですか。

    ASP.NET Web ページにおけるページ間ポスティング
    http://msdn.microsoft.com/ja-jp/library/ms178139(v=vs.100).aspx

    具体的には以下のような感じです。

    Source ページ

     
    <%@ 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">
        protected void Page_Load(object sender, EventArgs e)
        {
            string token = "ebf9279bba7a7466c97aa8a136919b70";
            Session["TRANSACTION_TOKEN_KEY"] = token;
            ViewState["TOKEN_KEY"] = token;
            HiddenField1.Value = (string)ViewState["TOKEN_KEY"];
        }
    </script>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <h1>Source Page</h1>
            <asp:Button ID="Button1" 
                runat="server" 
                Text="Button" 
                PostBackUrl="~/154-CrossPagePostbackViewStateTarget.aspx" />
            <asp:HiddenField ID="HiddenField1" runat="server" />
        </div>
        </form>
    </body>
    </html>

    Target ページ

    <%@ 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">
    
        protected void Page_Load(object sender, EventArgs e)
        {
            Label1.Text = (string)Session["TRANSACTION_TOKEN_KEY"];        
            Label2.Text = Request.Form["HiddenField1"];
            Label3.Text = Label1.Text.Equals(Label2.Text).ToString();
    
            // これでは取得できない(PreviousPage.Items["TOKEN_KEY"] は null になる)
            Label4.Text = (PreviousPage.Items["TOKEN_KEY"] == null) ?
                    "null" : PreviousPage.Items["TOKEN_KEY"].ToString();       
        }
    </script>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <h1>Target Page</h1>
            Session: <asp:Label ID="Label1" runat="server"></asp:Label>
            <br />
            ViewState: <asp:Label ID="Label2" runat="server"></asp:Label>
            <br />
            Result: <asp:Label ID="Label3" runat="server"></asp:Label>
            <br />
            PreviousPage.Items["TOKEN_KEY"]: <asp:Label ID="Label4" runat="server"></asp:Label>
        </div>
        </form>
    </body>
    </html>


    • 編集済み SurferOnWww 2012年6月6日 12:57 誤記訂正
    • 回答の候補に設定 山本春海 2012年6月27日 9:06
    • 回答としてマーク 山本春海 2012年7月6日 7:08
    2012年6月6日 12:56
  • 僕も確認してみました。

    こちらでもSurferOnWwwさんと同じく、this.PreviousPage.Items[TOKEN_KEY]はnullになってしまいました。なにか特別な設定などがあるのでしょうか。

    #hidden項目としてBase64にエンコードされたViewStateの値が一緒にPOSTされてくるはずだから、Request["__VIEWSTATE"]を使ってどうにかできないかな。

    • 回答の候補に設定 山本春海 2012年6月27日 9:06
    • 回答としてマーク 山本春海 2012年7月6日 7:08
    2012年6月7日 0:31

すべての返信

  • 類似ケースとだけ書かれてもよくわからないのです。もうちょっと詳しく書いてもらえませんか?

    質問文から想像するに、せめてこのあたりの情報は欲しいです。

    • ASP.NETのWebアプリケーションでどのような検証を行おうとしているのか。
    • Chromeの場合どのように検証に失敗するのか。
    • SessionとViewState双方の値をASP:Labelなどに書きだしてみるとどうなっているのか。
    • 他のPCのChromeでも同様に検証に失敗するのか。
    2012年6月6日 4:10
  • ASP.NETのWebアプリケーションで画面遷移の検証を行おうとして、ViewStateとセッションに同じデータを入れてその双方を
    ナビゲートした先のページで比較して、検証という手順です。

    具体的にはPage.PreviousPageの中身とSessionを比較していますが、双方を吐き出してみると違う値になっているようです。

    その結果、NGとなっているようです。

    2012年6月6日 5:12
  • PreviousPageからViewStateって取得できるんですね。知らなかったです。

    ちなみにどんなコードになるんですか?

    2012年6月6日 5:59
  • 以下のような形で、トークンを設定し。

                    this.Session[TRANSACTION_TOKEN_KEY] = token;
                    this.ViewState[TOKEN_KEY] = token;

    遷移先のほうで

                object sessionToken = this.Session[TRANSACTION_TOKEN_KEY];
                object clientToken = this.PreviousPage.Items[TOKEN_KEY];

    として、ページコンテキストから拾ってきているようです。

    如何せん、自分で書いたコードではなく人の書いたコード、しかも、当時の担当者は不明という、確かに動いてはいるようです。

    まあ、この辺の作りも怪しいといえば怪しいのですが、

    2012年6月6日 6:24
  • そうやって取得できることを初めて知りました。

    最初の質問に戻るのですが、このあたりも教えて下さい。

    • Chromeの場合どのように検証に失敗するのか。
    • SessionとViewState双方の値をASP:Labelなどに書きだしてみるとどうなっているのか。
    • 他のPCのChromeでも同様に検証に失敗するのか。

    あと、実際の検証はどのように行なっているんですか?上の例だと if (sessionToken.Equals(clientToken)) とかやっている?

    2012年6月6日 9:02
  • 実際の検証はまさしく、if (sessionToken.Equals(clientToken))でして、

    取り出した二つのトークンが相違しています。

    具体的には

    sessionToken: ebf9279bba7a7466c97aa8a136919b70
    clientToken: dccc5a2bba90a03d40a2e840294cd4b6

    ということになっています。

    トークンの形式そのものはどちらも同一ですが、中身は食い違っています。

    恐らく、生成時期の違うものが比較されているのではないかと思います。外しているかもしれませんが。

    2012年6月6日 9:16
  • サーバー側での話しなので、ブラウザは関係ないと思いますが、間違いなく以下のコー
    ドで Chrome 以外では取得できたのでしょうか?

    > object clientToken = this.PreviousPage.Items[TOKEN_KEY];

    自分が試した環境(ASP.NET 4, IIS7, Vista SP2, VS2010 Pro)では、Chrome に限らず、
    主要なブラウザの最新版 IE9, Firefox 13.0, Chrome 19.0.1084.52, Safari 5.1.7,
    Opera 11.64 すべて同じく取得できませんでしたけど(結果は null になる)。

    以下のページの「メモ」に書いてあるように、"ソース ページの隠しフィールドに値を
    文字列として格納し、ターゲット ページの Request.Form を使用してアクセスします。"
    としてはいかがですか。

    ASP.NET Web ページにおけるページ間ポスティング
    http://msdn.microsoft.com/ja-jp/library/ms178139(v=vs.100).aspx

    具体的には以下のような感じです。

    Source ページ

     
    <%@ 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">
        protected void Page_Load(object sender, EventArgs e)
        {
            string token = "ebf9279bba7a7466c97aa8a136919b70";
            Session["TRANSACTION_TOKEN_KEY"] = token;
            ViewState["TOKEN_KEY"] = token;
            HiddenField1.Value = (string)ViewState["TOKEN_KEY"];
        }
    </script>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <h1>Source Page</h1>
            <asp:Button ID="Button1" 
                runat="server" 
                Text="Button" 
                PostBackUrl="~/154-CrossPagePostbackViewStateTarget.aspx" />
            <asp:HiddenField ID="HiddenField1" runat="server" />
        </div>
        </form>
    </body>
    </html>

    Target ページ

    <%@ 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">
    
        protected void Page_Load(object sender, EventArgs e)
        {
            Label1.Text = (string)Session["TRANSACTION_TOKEN_KEY"];        
            Label2.Text = Request.Form["HiddenField1"];
            Label3.Text = Label1.Text.Equals(Label2.Text).ToString();
    
            // これでは取得できない(PreviousPage.Items["TOKEN_KEY"] は null になる)
            Label4.Text = (PreviousPage.Items["TOKEN_KEY"] == null) ?
                    "null" : PreviousPage.Items["TOKEN_KEY"].ToString();       
        }
    </script>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <h1>Target Page</h1>
            Session: <asp:Label ID="Label1" runat="server"></asp:Label>
            <br />
            ViewState: <asp:Label ID="Label2" runat="server"></asp:Label>
            <br />
            Result: <asp:Label ID="Label3" runat="server"></asp:Label>
            <br />
            PreviousPage.Items["TOKEN_KEY"]: <asp:Label ID="Label4" runat="server"></asp:Label>
        </div>
        </form>
    </body>
    </html>


    • 編集済み SurferOnWww 2012年6月6日 12:57 誤記訂正
    • 回答の候補に設定 山本春海 2012年6月27日 9:06
    • 回答としてマーク 山本春海 2012年7月6日 7:08
    2012年6月6日 12:56
  • 僕も確認してみました。

    こちらでもSurferOnWwwさんと同じく、this.PreviousPage.Items[TOKEN_KEY]はnullになってしまいました。なにか特別な設定などがあるのでしょうか。

    #hidden項目としてBase64にエンコードされたViewStateの値が一緒にPOSTされてくるはずだから、Request["__VIEWSTATE"]を使ってどうにかできないかな。

    • 回答の候補に設定 山本春海 2012年6月27日 9:06
    • 回答としてマーク 山本春海 2012年7月6日 7:08
    2012年6月7日 0:31
  • 以下のような形で、トークンを設定し。

    this.Session[TRANSACTION_TOKEN_KEY] = token;
    this.ViewState[TOKEN_KEY] = token;

    遷移先のほうで

    object sessionToken = this.Session[TRANSACTION_TOKEN_KEY];
    object clientToken = this.PreviousPage.Items[TOKEN_KEY];

    として、ページコンテキストから拾ってきているようです。

     ViewState に設定しているが、Item から探そうとしているため、のように見えるのですが、違うのかなぁ?Items プロパティ ViewState プロパティでは、公開範囲も違うし、説明も違うし、型も違うようなので、同じものが取れるとは思えないのですが...もっとも、StateBag 型は IDictionary インターフェイスを実装していますから、Items プロパティと ViewState プロパティで同じオブジェクトを指している可能性もありますが。


    Jitta@わんくま同盟

    2012年6月11日 14:00