SqlMembershipProvider のハッシュ アルゴリズム

前回の Silverlight Business Application テンプレートの認証機能でパスワードに対するハッシュ アルゴリズムについて少し触れましたが、
今回は SqlMembershipProvider についてより詳しく記述してみます。
 
■ 使用されるハッシュ アルゴリズムを指定する方法
.NET Framework 4 の SqlMembershipProvider が使用するハッシュ アルゴリズムは、次のロジックで決まるようです。
  1. <membership> 要素の hashAlgorithmType 属性が
      a. 指定されているとき、その値。
      b. 指定されていないとき、<membership> – <providers> – <add> 要素の passwordCompatMode 属性が
            i. 指定されていないまたは Framework20 のとき、SHA1。
            ii. Framework40 のとき、<machineKey> 要素の validation 属性の値 (既定では HMACSHA256)。
  2. 上記の結果が MD5、AES または TripleDES のとき、SHA1。
従って、Web.config で何も指定しない場合、Membership.HashAlgorithmType で取得される値が HMACSHA256 であるにもかかわらず、
SqlMembershipProvider が使用するハッシュ アルゴリズムは SHA1 となります。
 
上記で登場した要素や属性をすべて記述した Web.config がこちらです。

  <system.web>
    <machineKey validation="HMACSHA256" />
    <membership defaultProvider="Default" hashAlgorithmType="HMACSHA256">
      <providers>
        <clear />
        <add passwordCompatMode="Framework40"
          name="Default" applicationName="BusinessApplication1" connectionStringName="Business1ConnectionString"
          type="System.Web.Security.SqlMembershipProvider, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
      </providers>
    </membership>
  </system.web>

 
passwordCompatMode 属性に指定できるのは、MembershipPasswordCompatibilityMode 列挙体の値です。
passwordCompatMode 属性は .NET Framework 4 で追加された SqlMembershipProvider 固有の属性であり、
まだあまり認知されていないと思いますが、ここに Framework40 を指定しないと validation 属性の値は反映されません。
(今のところ、MSDN ライブラリにもまだ記述がありません。検索してもヒットしません。)
 
結論として、<membership> 要素の hashAlgorithmType 属性を明示的に指定しておくのが一番わかりやすい方法であると考えられます。
逆に、ここの値を指定しておけば他の部分を指定する必要はありません。
 
また、SHA1 については脆弱性が指摘されており、より強度のあるアルゴリズムが推奨されるため、
HMACSHA256 や SHA256 などを指定することが望ましいです。
 
■ ハッシュ化のためのコード
SqlMembershipProvider は、ハッシュの強度を増すために、
ソルトと呼ばれるユーザーごとに与えられるデータと組み合わせてパスワードをハッシュ化します。
 
SqlMembershipProvider では、だいたい以下のような処理が実行されています。
SqlMembershipProvider を使わずに認証ロジックを自作したいという場合にも、これらのコードが参考になると思います。

static void Main()
{
    string hashedPassword = Hash("P@ssw0rd", "j44YfP/l4cC9OTxsBiiQ+w==");
}

private static string hashAlgorithmName = "HMACSHA256"; // 変更可能
private static Encoding encoding = Encoding.Unicode;

public static byte[] Hash(byte[] data, byte[] salt)
{
    using (HashAlgorithm hashAlgorithm = HashAlgorithm.Create(hashAlgorithmName))
    {
        if (hashAlgorithm is KeyedHashAlgorithm)
        {
            KeyedHashAlgorithm keyedHashAlgorithm = (KeyedHashAlgorithm)hashAlgorithm;

            keyedHashAlgorithm.Key = Enumerable.Range(0, keyedHashAlgorithm.Key.Length)
                 .Select(i => salt[i % salt.Length]).ToArray();

            return keyedHashAlgorithm.ComputeHash(data);
        }
        else
        {
            byte[] saltedData = salt.Concat(data).ToArray();

            return hashAlgorithm.ComputeHash(saltedData);
        }
    }
}

public static string Hash(string text, string salt)
{
    return Convert.ToBase64String(Hash(encoding.GetBytes(text), Convert.FromBase64String(salt)));
}

// ランダムなソルトを生成します。
// SqlMembershipProvider では 16 バイトです。
public static string GenerateSalt()
{
    return Convert.ToBase64String(GenerateRandomByteArray(16));
}

// ランダムなバイト配列を生成します。
public static byte[] GenerateRandomByteArray(int size)
{
    byte[] data = new byte[size];

    RandomNumberGenerator.Create().GetBytes(data);

    return data;
}


 
ちなみに、暗号アルゴリズムの名前と具象クラスのマッピングの一覧は、
CryptoConfig クラスの DefaultNameHT プロパティ (プライベートかつ静的) で見ることができます。
 
バージョン情報
.NET Framework 4
 
参照
広告
カテゴリー: .NET Framework. タグ: . 2 Comments »

Silverlight Business Application テンプレートの認証機能

Visual Studio 2010 の Silverlight 4 用のプロジェクト テンプレートの中に [Silverlight Business Application] というものがあります。
認証機能を含み、Silverlight で業務アプリケーションを構築する場合の全体像を示したテンプレートといえます。
しかし、このプロジェクトを作成して即座に実行しても、認証機能が正しく動作するわけではありません。
 
以下では、この認証機能が動作するのに必要な手順を示します。
ASP.NET メンバーシップを利用します。
SQL Server のインスタンスは localhost\SQLEXPRESS とし、[Business1] データベースが作成されているものとします。
  1. コマンド プロンプトを起動し、次のコマンドを実行する。

    set regsql=%SystemRoot%\Microsoft.NET\Framework\v4.0.30319\aspnet_regsql.exe
    %regsql% -S localhost\SQLEXPRESS -E -d Business1 -A mrp


      → [Business1] データベースにテーブルがいくつか作成される。
  2. Visual Studio を起動する。
  3. [ファイル] – [新規作成] – [プロジェクト] をクリックし、
    テンプレートから [Silverlight Business Application] を選択して [OK] をクリックする。
      → ソリューションおよびプロジェクトが作成される。
  4. (1) BusinessApplication1.Web プロジェクトの Web.config をダブルクリックする。
    (2) <connectionStrings>, <membership>, <roleManager>, <profile> 要素を次のように構成する。



    ・・・ (省略) ・・・

      <
    connectionStrings>
        <add name="Business1ConnectionString"
          connectionString="Data Source=localhost\SQLEXPRESS;Initial Catalog=Business1;Integrated Security=True"
          providerName="System.Data.SqlClient" />
      </connectionStrings>

      <system.web>

    ・・・ (省略) ・・・

        <membership defaultProvider="Default" hashAlgorithmType="HMACSHA256">
          <providers>
            <clear />
            <add name="Default" applicationName="BusinessApplication1" connectionStringName="Business1ConnectionString"
               type="System.Web.Security.SqlMembershipProvider, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
          </providers>
        </membership>

        <roleManager defaultProvider="Default" enabled="true">
          <providers>
            <clear />
            <add name="Default" applicationName="BusinessApplication1" connectionStringName="Business1ConnectionString"
               type="System.Web.Security.SqlRoleProvider, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
          </providers>
        </roleManager>

        <profile defaultProvider="Default">
          <providers>
            <clear />
            <add name="Default" applicationName="BusinessApplication1" connectionStringName="Business1ConnectionString"
               type="System.Web.Profile.SqlProfileProvider, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
          </providers>
          <properties>
            <add name="FriendlyName" />
          </properties>
        </profile>

      </system.web>

    ・・・ (省略) ・・・


  5. [デバッグ] – [デバッグなしで開始] をクリックする。
      → 作成されたアプリケーションが起動する。
これで、とりあえずアプリケーションは完成です。
右上の [login] をクリックするとログイン画面が現れますが、まだユーザーを作成していないので左下の [Register now] をクリックします。
 
 
正常に入力したら [OK] をクリックします。
 
 
ユーザーの作成とログインが完了しました。
[Friendly name] の値は表示用に使用されます。
次回以降は、ログイン画面でユーザー名とパスワードを入力すればログインできます。
 
注意点
(1) aspnet_regsql.exe の -A スイッチでは、m はメンバーシップ、r はロール マネージャー、p はプロファイルを表します。
     他に、c (Web パーツのパーソナル化) および w (Web イベント) があります。
 
(2) aspnet_regsql.exe により作成されたテーブルを削除するには、-A の代わりに -R を使用します。
%regsql% -S localhost\SQLEXPRESS -E -d Business1 -R mrp -Q
     -Q は確認メッセージが表示されないことを示します。
 
(3) aspnet_regsql.exe により作成されたテーブルには、
     パスワードをハッシュ化したり、プロファイルのデータを特殊な形式に加工したりして格納しなければなりません。
     従って、あらかじめ初期データを (Excel などで) 自分で作成しておいてそのままインポートするというのは難しいです。
     初期データを作成する場合にも、このテンプレートの UserRegistrationService クラスにあるような
     コード (Membership.CreateUser メソッドなど) を利用するのがよいでしょう。
 
(4) ログインすると認証 Cookie が発行されますが、これは ASP.NET の通常の Web アプリケーションで発行されるものと同じです。
     従って、同じ BusinessApplication1.Web の中では Silverlight 以外のページ (.aspx ファイルなど) ともログイン状態が共有されます。
 
(5) <membership> 要素の hashAlgorithmType 属性に HMACSHA256 を指定しています。
     この属性を指定しない場合、パスワードに対する既定のハッシュ アルゴリズムとして SHA1 が使用されます。
     しかし SHA1 については脆弱性が指摘されており、より強度のあるアルゴリズムが推奨されるため、
     明示的に HMACSHA256 や SHA256 などを指定することが望ましいです。
     (SqlMembershipProvider のハッシュ アルゴリズムに詳細を記述しました。)
 
     なお、<membership> – <providers> – <add> 要素の passwordFormat 属性を指定することにより、
     ハッシュ化 (Hashed) だけでなく、平文そのまま (Clear) や暗号化 (Encrypted) といった手段も選べます。
     暗号化を利用する場合、<machineKey> 要素の decryptionKey 属性にキーを明示的に指定する必要があります。
 
(6) サービスに対する認証および承認が必要な場合には、ドメイン サービス クラスに対して次の属性を使用します。
  • RequiresAuthenticationAttribute: 匿名ユーザーでない (ログイン済である) ことを要求します。
    Web.config の <deny users="?" /> に相当します。
  • RequiresRoleAttribute: 特定のロールに属していることを要求します。
    Web.config の <allow roles="roleNames" /> に相当します。
     以下に例を示します。

[EnableClientAccess]
public class DomainService1 : DomainService
{
    [RequiresAuthentication]
    public string GetMessageForAuthenticatedUsers()
    {
        dynamic profile = HttpContext.Current.Profile;

        return string.Format("ようこそ {0} !", profile.FriendlyName);
    }

    [RequiresRole("UltimateUsers")]
    public string GetMessageForUltimateUsers()
    {
        dynamic profile = HttpContext.Current.Profile;

        return string.Format("ようこそ {0} 様 !!", profile.FriendlyName);
    }

}

 
バージョン情報
Silverlight 4
.NET Framework 4
Visual Studio 2010 + Silverlight 4 Tools
SQL Server 2005, 2008, 2008 R2
 
 

Parallel.For メソッドの挙動

.NET Framework 4 で追加されたタスク並列ライブラリ (TPL) の Parallel.For メソッドは、
従来の BeginInvoke メソッドなどとは異なり、呼び出し元のスレッドをブロックします。
 
簡単な内容ですが、今回はこの事実を確かめてみることにします。
C# で次のようなコンソール アプリケーションを作成しました。
各スレッドでは 1 秒間だけ待機させます。

static void Main()
{
    WriteLog("開始");

    Parallel.For(0, 10, (i) =>
    {
        Thread.Sleep(1000);

        WriteLog(i + " 番目のスレッド終了");
    });

    WriteLog("終了");
}

static void WriteLog(string message)
{
    Console.WriteLine("{0:HH:mm:ss.fff}: {1}", DateTime.Now, message);
}


 
このプログラムを実行すると、コマンドライン上に次のように出力されました。
16:45:23.638: 開始
16:45:24.649: 0 番目のスレッド終了
16:45:24.649: 5 番目のスレッド終了
16:45:25.360: 1 番目のスレッド終了
16:45:25.651: 2 番目のスレッド終了
16:45:25.651: 6 番目のスレッド終了
16:45:26.362: 4 番目のスレッド終了
16:45:26.652: 3 番目のスレッド終了
16:45:26.652: 7 番目のスレッド終了
16:45:26.863: 8 番目のスレッド終了
16:45:27.363: 9 番目のスレッド終了
16:45:27.363: 終了
この結果により、Parallel.For メソッドがすべてのスレッドの終了を待機することがわかりました。
 
バージョン情報
.NET Framework 4
 
参照
カテゴリー: .NET Framework. タグ: . Leave a Comment »

bcp ユーティリティによるデータのエクスポートおよびインポート

SQL Server 上のテーブルのデータをテキスト形式のファイルにエクスポートしたり、
逆にインポートしたりする方法について記述します。
 
SQL Server 認証を使用して、Table1, Table2 テーブルのデータを Unicode かつカンマ区切り形式のファイルとして
それぞれ Table1.csv, Table2.csv にエクスポートするには、以下のようなコマンドを実行します。

@echo off
 
set dbServer=localhost\SQLEXPRESS
set dbUser=user1
set dbPassword=P@ssw0rd
 
bcp [Database1].[dbo].[Table1] out Table1.csv -S %dbServer% -U %dbUser% -P %dbPassword% -w -t ,
bcp [Database1].[dbo].[Table2] out Table2.csv -S %dbServer% -U %dbUser% -P %dbPassword% -w -t ,
 
pause

 
逆に、Table1.csv, Table2.csv のデータをそれぞれ Table1, Table2 テーブルにインポートするには、out を in に変更するだけです。

@echo off
 
set dbServer=localhost\SQLEXPRESS
set dbUser=user1
set dbPassword=P@ssw0rd
 
bcp [Database1].[dbo].[Table1] in Table1.csv -S %dbServer% -U %dbUser% -P %dbPassword% -w -t ,
bcp [Database1].[dbo].[Table2] in Table2.csv -S %dbServer% -U %dbUser% -P %dbPassword% -w -t ,
 
pause

 
注意点
(1) Windows 認証を使用する場合は、-U および -P の代わりに -T を使用します。
bcp [Database1].[dbo].[Table1] out Table1.csv -S %dbServer% -T -w -t ,
(2) 「-w」の部分は Unicode 形式で出力することを示します。
他の文字エンコーディングで出力する場合は、「-c -C codepage」を指定します。
「-C codepage」を省略した場合は Shift_JIS となります。
例えば、UTF-8 で出力する場合は次のようにします。
bcp [Database1].[dbo].[Table1] out Table1.csv -S %dbServer% -U %dbUser% -P %dbPassword% -c -C 65001 -t ,
ただし、試してみたところ、どの文字エンコーディングでも利用可能というわけではないようです。
利用可: Shift_JIS (932)、JIS (20932)、ISO-2022-JP (50220)、UTF-8 (65001)
利用不可: Unicode (1200)、Unicode ビッグ エンディアン (1201)、EUC-JP (51932)
なお、Excel で CSV ファイルとして開く場合には、Shift_JIS でないと正常に読み込めません。
また、-w、-c の他に、-n (ネイティブ形式) および -N (Unicode ネイティブ形式) があります。
 
(3) 「-t ,」の部分はカンマ区切りであることを示します。省略した場合はタブ区切りとなります。
 
(4) NULL 値は空文字列として出力され、空文字列は \0 (16 進表記で 00 の制御文字) として出力されます。
 
(5) リレーションシップがある場合、親テーブルから先にインポートする必要があります。
 
(6) テーブル名を動的に取得する方法については、PowerShell でデータベースのすべてのデータをエクスポートするをご覧ください。
 
バージョン情報
SQL Server 2005, 2008, 2008 R2
 
 
カテゴリー: データベース. タグ: , . 1 Comment »