WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

Froms 認証クッキーの永続化

by WebSurfer 2011年12月3日 13:29

ASP.NET 標準の Forms 認証に使用される認証クッキーの「永続化」については、先の記事 永続的ってデフォルトで 30 分? に書きましたが、続けて「永続化」した時としない時の動作の違いを備忘録として書いておきます。

まず、ログインに成功した時にサーバーからブラウザに送られる認証クッキーですが、「永続化」した場合は以下のよう expires によって有効期限が指定されます。「永続化」しない場合は認証クッキーに expires=...; が存在しません。

Set-Cookie: .ASPXAUTH=...; expires=Wed, 30-Nov-2011 13:21:29 GMT; path=/; HttpOnly

expires の日時は、ログインに成功した時点から authentication の forms 要素 の timeout 属性で設定した時間(デフォルトで 30 分)だけ先の日時になります。

認証クッキーは認証チケットの入れ物に過ぎないことに注意してください。認証チケットの有効期限は、ユーザー名などの他の情報と一緒に暗号化されて、認証チケットの中に含まれています。

[永続化」した場合の認証クッキーの有効期限は、認証チケットの有効期限と同じになりますが、認証クッキーの有効期限で認証チケットの有効期限を判定しているわけではありません(そもそも、サーバー側ではクライアントから送られてきたクッキーの有効期限はわかりません)。

認証チケットが発行された以降、有効な認証チケットがブラウザからの要求と一緒にサーバーに送られてくれば、サーバーはユーザーを認証済みと見なし、匿名アクセスが許可されてないページへのアクセスを許可します。

認証チケットが送られてこない場合、もしくは送られてきた認証チケットが期限切れの場合、サーバーはユーザーをログイン画面へリダイレクトします。

slidingExpiration が true になっている場合、timeout 属性で設定した時間の半分を過ぎてアクセスすると、有効期限が延長された認証チケット/クッキーが再発行されます。「永続化」している場合は、expires=...; も延長されて認証クッキーが再発行され、クライアントの HDD 上の既存の認証クッキーが上書きされます。

認証クッキーを「永続化」した場合としない場合(即ち、認証クッキーの有効期限の有無)では、以下のように動きが異なります。

「永続化」した場合

クッキーに有効期限がある(即ち、Set-Cookie: に expires=...; が指定される)ので、ブラウザはクッキーを HDD に保存します。

ブラウザを閉じたり Windows をシャットダウンしたりしても、再度ブラウザを立ち上げてアクセスすれば、ブラウザは認証クッキーを HDD から取得してサーバーに送ります。

クッキーの有効期限が切れると、ユーザーが次にサイトを訪問した時にブラウザによって削除されます。

次回アクセスする際にログイン操作の手間が省けるということが「永続化」のメリットですが、timeout をデフォルトの 30 分程度の短い時間に設定した場合はほとんど意味がないです。

ちなみに、BlogEngine.NET のオリジナルの web.config では timeout="129600"(90 日)に設定してありました。「永続化」もこのぐらい長ければ役に立つと思いますが。

でも、セキュリティ上は、timeout をできるだけ短い時間に、ついでに slidingExpiration は false に設定しておく方がよさそうです。

「永続化」しない場合

この場合、認証クッキーはブラウザのメモリにしか保持されません。従って、ブラウザを閉じれば認証クッキーは消えます。

逆に、ブラウザを閉じなければ認証クッキーは消えません。要求のたびに送られ続けます。(ただし、中身の認証チケットが有効かどうかは別の話で、timeout の設定によります)

Tags: , ,

Authentication

永続的ってデフォルトで 30 分?

by WebSurfer 2011年11月25日 22:57

ASP.NET の標準の Forms 認証で、Login コントロールを使用してログインのページを作ると、デフォルトで [次回のために保存] チェックボックスが表示されます。

フォーム認証のログイン画面

これにチェックを入れてログインすると永続的な cookie が発行される、と MSDN ライブラリなどに書いてあります。

永続的というのは、cookie の有効期限が 50 年だからというのはあちこちで目にするので(例:Login.RememberMeSet プロパティASP.NET の組み込み機能を活用し、Web 攻撃を回避する)、信じて疑わなかったのですが、どうやら間違い(修正漏れ?)のようです。

[次回のために保存] チェックボックスをオン(Login.RememberMeSet を true)に設定してログインすると、Set-Cookie: ヘッダーに expires が指定されますが、それは 50 年先ではなく、timeout で設定した時間(デフォルトで 30 分)だけ先の時間になりました。

「永続的ってデフォルトで 30 分なの?」って感じです。(苦笑)

MSDN ライブラリの authentication の forms 要素 (ASP.NET 設定スキーマ) のメモに "ASP.NET V1.1 の場合、永続的な Cookie は timeout 属性の設定に関係なくタイムアウトしません。一方、ASP.NET V2.0 の場合、永続的な Cookie は timeout 属性に従ってタイムアウトします。" とありますが、どうやらこれが正しいようです。

なお、認証クッキーの中にある認証チケットの有効期限は認証クッキーの有効期限と同じに設定され、slidingExpiration も期待通り動く(有効期限が延長されたクッキーが発行される)のは確認しました。

Tags: ,

Authentication

リストボックスのスクロール位置を維持

by WebSurfer 2011年11月20日 15:47

リストボックスの内のアイテムのスクロール位置をポストバック前後で維持する方法です。IE9, Firefox 8.0, Safari 5.1.1, Opera 11.52 で検証してみましたが、Opera 以外は期待通りの動きをしました。(Opera では scrollTop が取得できず、うまくいきません。他の方法を検討中です)(2011/11/21 追記: IE6 もダメでした。IE7, IE8 は OK でした)

ListBox のスクロール位置を保持

IE ではリストボックスの中の項目を選択するしないにかかわらず、ポストバックすると一番先頭に戻ってしまいます。その他のブラウザでは、リストボックスの中の項目を選択すればポストバック後に一番先頭に戻ることはありませんが、スクロール位置はポストバック前後で変わってしまいます。

今回の例では、JavaScript の scrollTop を使用して、ポストバック直前のリストボックスのスクロールバーの上端の座標を取得して隠しフィールドに保存し、ポストバックして再描画する時に隠しフィールドに保存した座標を取得してスクロール位置を設定しています。

そのサンプルコードは以下の通りです。上の画像は、このコードを実行したときのブラウザの仮面です。実際に動かして試せるよう 実験室 にアップしましたので、興味のある方は試してみてください。

隠しフィールドには ASP.NET の HiddenField サーバーコントロールを使いました。これを使うと自動的に ViewState によってポストバック前後の Value が維持されます。普通の html の <input type="hidden" ... /> を使う場合は、ポストバック前後の value の維持に一工夫必要です。

リストボックスには、これも ASP.NET の ListBox サーバーコントロールを使っていますが、スクロール位置をポストバック前後で維持する仕組みに関しては、普通の html の select でも同じです。

<%@ 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">
  void SubmitBtn_Click(Object sender, EventArgs e)
  {
    string selectedItems = String.Empty;
    int count = 0;

    for (int i = 0; i < ListBox1.Items.Count; i++)
    {
      if (ListBox1.Items[i].Selected)
      {
        selectedItems += ListBox1.Items[i].Value + ", ";
        count++;
      }
    }

    if (count > 0)
    {
      selectedItems =
        selectedItems.TrimEnd(new char[] { ',', ' ' });
      Label2.Text = "You chose: " + selectedItems;
    }
    else
    {
      Label2.Text = "アイテムが選択されていません。";
    }
  }

  protected void Page_Load(object sender, EventArgs e)
  {
    string value = HiddenField1.Value;
    Label1.Text = "Scroll Top: " + value;
  }

</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <title></title>
  <script src="Scripts/jquery-1.4.1.js" type="text/javascript">
  </script>
  <script type="text/javascript">
  //<![CDATA[

  // Opera 11.52 で動かない(scrollTop が取得できない)
  function setScrollTopInHiddenField() {
    var position =
      document.getElementById("<%=ListBox1.ClientID%>").scrollTop;
    document.getElementById("<%=HiddenField1.ClientID%>").value = 
      position;
  }

  window.onload = function () {
    var position =
      document.getElementById("<%=HiddenField1.ClientID%>").value;
    if (position != "") {
      document.getElementById("<%=ListBox1.ClientID%>").scrollTop = 
        position;
    }
  }

  // jQuery を使っても、やはり Opera では動かない
//  function setScrollTopInHiddenField() {
//    var position = 
//      $("#<%=ListBox1.ClientID%>").scrollTop();
//    $("#<%=HiddenField1.ClientID%>").val(position);
//  }

//  $(document).ready(function () {
//    var position = 
//      $("#<%=HiddenField1.ClientID%>").val();
//    if (position != "") {
//      $("#<%=ListBox1.ClientID%>").scrollTop(position);
//    }
//  });

    //]]>
    </script>

</head>
<body>
  <form id="form1" runat="server">
  <div>
    <asp:HiddenField ID="HiddenField1" runat="server" />
    <asp:Label ID="Label1" runat="server">
    </asp:Label>
    <br />
    <asp:ListBox id="ListBox1" 
      Rows="10"
      SelectionMode="Multiple" 
      runat="server">
      <asp:ListItem>Item 1</asp:ListItem>
      <asp:ListItem>Item 2</asp:ListItem>
      <asp:ListItem>Item 3</asp:ListItem>
      <asp:ListItem>Item 4</asp:ListItem>
      <asp:ListItem>Item 5</asp:ListItem>
      <asp:ListItem>Item 6</asp:ListItem>
      <asp:ListItem>Item 7</asp:ListItem>
      <asp:ListItem>Item 8</asp:ListItem>
      <asp:ListItem>Item 9</asp:ListItem>
      <asp:ListItem>Item 10</asp:ListItem>
      <asp:ListItem>Item 11</asp:ListItem>
      <asp:ListItem>Item 12</asp:ListItem>
      <asp:ListItem>Item 13</asp:ListItem>
      <asp:ListItem>Item 14</asp:ListItem>
      <asp:ListItem>Item 15</asp:ListItem>
      <asp:ListItem>Item 16</asp:ListItem>
      <asp:ListItem>Item 17</asp:ListItem>
      <asp:ListItem>Item 18</asp:ListItem>
      <asp:ListItem>Item 19</asp:ListItem>
      <asp:ListItem>Item 20</asp:ListItem>
      <asp:ListItem>Item 21</asp:ListItem>
      <asp:ListItem>Item 22</asp:ListItem>
      <asp:ListItem>Item 23</asp:ListItem>
      <asp:ListItem>Item 24</asp:ListItem>
      <asp:ListItem>Item 25</asp:ListItem>
    </asp:ListBox>

    <asp:button id="Button1"
      Text="Submit" 
      OnClick="SubmitBtn_Click" 
      OnClientClick="setScrollTopInHiddenField();"
      runat="server" />
    <br />
    <asp:Label ID="Label2" runat="server">
    </asp:Label>
  </div>
  </form>
</body>
</html>

@ Page ディレクティブに MaintainScrollPositionOnPostback 属性というものがありますが、たぶんこんな感じでポストバック前後の位置を維持しているのではないかと思います。


------ 2016/1/12 追記 ------

MaintainScrollPositionOnPostBack(ポストバック前後で上下左右のスクロール位置を維持する機能)の仕組みを調べてみました。

やはり、この記事に書いたようなスクロール位置を保存する隠しフィールドとクライアントスクリプトを使用しています。

MaintainScrollPositionOnPostBack でスクロール位置を維持する仕組みについては別の記事「ポストバック前後でスクロール位置維持」に書きましたので興味がありましたら見てください。

Tags: ,

JavaScript

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。

Calendar

<<  2024年4月  >>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

View posts in large calendar