Webセキュリティの小部屋

Twitter のフォローはこちらから Facebook ページはこちら RSSフィードのご登録はこちらから
公開日:2013年3月9日
最終更新日:2020年8月13日

セッション管理の不備と対策(ASP.NET,C#,VB.NET編)

セッション管理の不備に対する根本的対策は、以下の記事を参照してください。

これを ASP.NET で実現すると以下のようになります。

■1.推測困難なセッション ID を利用する
ASP.NET のセッション ID の生成は特に問題ないので、ASP.NET のセッション ID 作成機能を利用します。

■2.セッション ID を URL に含めない
ASP.NET はデフォルトでセッション ID を URL に含みません。

■3.HTTPS 通信で利用する Cookie には secure 属性を付与する
ASP.NET で Cookie に secure 属性を付与するには以下のように記述します。HttpOnly 属性も付与したほうがよいでしょう。

・C#

HttpCookie cookie = new HttpCookie("sample", "value");
cookie.Secure = true;
cookie.HttpOnly = true;
Response.Cookies.Add(cookie);

・VB.NET

Dim cookie As HttpCookie = New HttpCookie("sample", "value")
cookie.Secure = True
cookie.HttpOnly = True
Response.Cookies.Add(cookie)

レスポンスヘッダーには以下のように出力されます。

Set-Cookie: sample=value; path=/; secure; HttpOnly

セッション ID に secure 属性と HttpOnly 属性を付与する方法は以下の記事を参照してください。

■4-1.ログイン後にセッションを新規に開始する
■4-2.ログイン後にセッション ID とは別の秘密情報を持ち、各ページでその値をチェックする
ASP.NET にはセッション ID を振り直す機能がないため 4-1 は採用できません。そのため、ASP.NET では 4-2 の方法を採用します。

秘密情報は CSRF の独自トークンと同じ要件なので、CSRF の独自トークンを作成するクラスを流用します。詳しくは以下の記事を参照してください。

下図の簡単なログイン機能を作成します。

login

・Login.aspx(C#)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace TestCS
{
  public partial class Login : System.Web.UI.Page
  {
    protected void ButtonLogin_Click(object sender, EventArgs e)
    {
      //パラメーター取得
      string id = this.TextBoxID.Text;
      string passwword = this.TextBoxPassword.Text;

      //簡易ログイン
      if (id == "yamada" && passwword == "pass")
      {
        //ログイン成功

        //トークン作成
        string token = Token.GetToken();
        HttpCookie tokenCookie = new HttpCookie("token", token);
        tokenCookie.Secure = true;
        tokenCookie.HttpOnly = true;
        Response.Cookies.Add(tokenCookie);

        //セッションに値格納
        Session["id"] = id;
        Session["token"] = token;

        //リダイレクト
        Response.Redirect("Welcome.aspx");
      }
    }
  }
}

・Login.aspx(VB.NET)

Public Class Login1
  Inherits System.Web.UI.Page

  Protected Sub ButtonLogin_Click(sender As Object, e As EventArgs) Handles ButtonLogin.Click
 
    'パラメーター取得'
    Dim id As String = Me.TextBoxID.Text
    Dim password As String = Me.TextBoxPassword.Text

    '簡易ログイン'
    If id = "yamada" And password = "pass" Then
      'ログイン成功'

      'トークン作成'
      Dim myToken As String = Token.GetToken()
      Dim tokenCookie As HttpCookie = New HttpCookie("token", myToken)
      tokenCookie.Secure = True
      tokenCookie.HttpOnly = True
      Response.Cookies.Add(tokenCookie)

      'セッションに値格納'
      Session("id") = id
      Session("token") = myToken

      'リダイレクト'
      Response.Redirect("Welcome.aspx")
    End If

  End Sub
End Class

・Tokenクラス(C#)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Text;
using System.Security.Cryptography;

namespace TestCS
{
  public class Token
  {
    private static int TOKEN_LENGTH = 16; //16*2=32バイト

    //32バイトのトークンを作成
    public static string GetToken()
    {
      byte[] token = new byte[TOKEN_LENGTH];

      RNGCryptoServiceProvider gen = new RNGCryptoServiceProvider();
      gen.GetBytes(token);

      StringBuilder buf = new StringBuilder();

      for (int i = 0; i < token.Length; i++)
      {
        buf.AppendFormat("{0:x2}", token[i]);
      }

      return buf.ToString();
    }
  }
}

・Tokenクラス(VB.NET)

Imports System.Security.Cryptography

Public Class Token
  Private Shared TOKEN_LENGTH As Integer = 15 '16*2=32バイト'

  '32バイトのトークンを作成'
  Public Shared Function GetToken() As String
    Dim token As Byte() = New Byte(TOKEN_LENGTH) {}

    Dim gen As RNGCryptoServiceProvider = New RNGCryptoServiceProvider()
    gen.GetBytes(token)

    Dim buf As StringBuilder = New StringBuilder()

    For i As Integer = 0 To token.Length - 1
      buf.AppendFormat("{0:x2}", token(i))
    Next

    Return buf.ToString()
  End Function
End Class

・Welcome.aspx(C#)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace TestCS
{
  public partial class Welcome : System.Web.UI.Page
  {
    protected void Page_Load(object sender, EventArgs e)
    {
      //トークンチェック
      HttpCookie token = Request.Cookies["token"];

      if ((token == null) || 
        (Request.Cookies["token"].Value != ((string)Session["token"])))
      {
        //エラーの場合はログイン画面にリダイレクト
        Response.Redirect("Login.aspx");
      }

       this.LabelID.Text = HttpUtility.HtmlEncode((string)Session["id"]);
    }
  }
}

・Welcome.aspx(VB.NET)

Public Class Welcome
  Inherits System.Web.UI.Page

  Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    'トークンチェック'
    Dim token As HttpCookie = Request.Cookies("token")

    'エラーの場合はログイン画面にリダイレクト'
    If (IsNothing(token)) Then
      Response.Redirect("Login.aspx")
    ElseIf Request.Cookies("token").Value <> CType(Session("token"), String) Then
      Response.Redirect("Login.aspx")
    End If

    Me.LabelID.Text = HttpUtility.HtmlEncode(CType(Session("id"), String))
  End Sub

End Class

参考

Webアプリケーションセキュリティに関する記事は、以下のページにまとまっています。ぜひご確認ください。


スポンサーリンク





カテゴリー:Webアプリケーションセキュリティ対策

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA