japan.internet.comThe Internet & IT Network
RSS
  • ニュース
  • コラム
  • リサーチ
  • ヘッドライン
  • 特集
  • ブログ
  • プレスリリース
  • 専門チャンネル
  • イベント
  • ランキング
  • ニュースメール
2008年10月14日
文字サイズ文字サイズ小文字サイズ中文字サイズ大
デベロッパー コラム2006年1月31日 10:00
4 Guys From Rolla
4 Guys From Rolla japan.internet.com 編集部メールホームrss
米国 Jupitermedia が運営する、ASP と ASP ネットワーク情報に関するサイト。

ASP.NETを使ってランダムなパスワードを生成する

海外海外internet.com発の記事

はじめに

 私は現在、あるコンサルティング案件で、ユーザーアカウントを使用するWebサイトに携わっています。このサイトでは、ユーザーアカウントの作成方法が2種類あります。1つはユーザー自身で作成する方法で、この場合、ユーザーは電子メールアドレスとパスワードを入力します。もう1つはユーザーの上司が作成する方法で、この場合、上司はユーザーの電子メールアドレスだけを入力します。すると、サイトがユーザー用にランダムなパスワードを生成し、そのパスワードをユーザーに電子メールで通知します。ユーザーは最初のログイン時に、このランダムなパスワードを変更しなければなりません。

 この方式を実現するためには、ランダムなパスワードを生成するプログラムを書くことが必要でした。そこで、4Guysで"random password"という言葉を検索してみました。残念ながら、ランダムなパスワードの生成について4Guysで見つかった記事はクラシックASP時代の古いものばかりだったので、自分でASP.NETのランダムパスワードジェネレータを書く必要がありました。この必要性については「ASP.NET 2.0’s new Membership API」で取り上げられており、実際のところ、ASP.NET 2.0ではMembership.GeneratePassword(length, numberOfNonAlphaNumericCharacters)を呼び出すだけで済みます。

 この記事では、ASP.NET用のランダムパスワードジェネレータについて紹介します。ランダムなパスワードを生成するにはいろいろなテクニックがあり、これらのテクニックについてソースコードを示しながら解説します。それでは始めましょう。

GUIDを使った手っ取り早いランダムなパスワードの生成

 ASP.NETを使ってランダムなパスワードを生成する最も簡単な方法は、GUIDの一部を取得することです。GUIDとはGlobally Unique ID(世界で唯一のID)のことで、1つのメソッド呼び出しですぐに生成できる128ビットの数値です。これを使えば、ランダムなパスワードとして使える16進数の文字列を生成することができます。GUIDを新たに生成するには、System.Guid構造体のNewGuid()メソッドを使用します。生成したGUIDは.ToString()メソッドを使って文字列に変換することができます。サンプルコードを以下に示します。

’ VB.NET
Dim guidResult as String = System.Guid.NewGuid().ToString()
// C#
string guidResult = System.Guid.NewGuid().ToString();

 このコードを実行するたびに新しいGUIDが生成されます。以下はこのコードを5回実行した場合の結果です。

2fedf13b-8f3d-4c6c-9e36-14885736ed92
bf24060b-0698-4bce-9d0f-c37df2d24508
99931723-a1b6-44be-b4b1-8826dd6f8ceb
5f509578-e1ef-41f2-b3ea-d94caffdcd0e
b4e7b807-09a8-4c77-bbfe-28b31f2093dc

 私は通常、ハイフン(-)を取り除いてGUIDの最初のn文字を取得します。このテクニックを一般の用途に使えるように、GetRandomPasswordUsingGUID(length)というメソッドを作ってみましょう。このメソッドでは、ランダムなパスワードの長さを入力し、GUIDの最初のlength文字(ハイフンを除く)を返します。

’ VB.NET
Public Function GetRandomPasswordUsingGUID(ByVal length as Integer) _
  as String  

  ’Get the GUID
  Dim guidResult as String = System.Guid.NewGuid().ToString()
  
  ’Remove the hyphens
  guidResult = guidResult.Replace("-", String.Empty)
  
  ’Make sure length is valid
  If length <= 0 OrElse length > guidResult.Length Then
    Throw New ArgumentException( _
      "Length must be between 1 and " & guidResult.Length)
  End If
  
  ’Return the first length bytes
  Return guidResult.Substring(0, length)
End Function
// C#
public string GetRandomPasswordUsingGUID(int length)
{
  // Get the GUID
  string guidResult = System.Guid.NewGuid().ToString();
  
  // Remove the hyphens
  guidResult = guidResult.Replace("-", string.Empty);
  
  // Make sure length is valid
  if (length <= 0 || length > guidResult.Length)
    throw new ArgumentException(
      "Length must be between 1 and " + guidResult.Length);
  
  // Return the first length bytes
  return guidResult.Substring(0, length);

 以下はlengthの値をそれぞれ51015にしてこのメソッドを呼び出した結果です。

Random password of length 5:ce7e9
Random password of length 10: 578562009e
Random password of length 15: 7b0fc1bc9ea9486

さらに強力なランダムパスワードジェネレータ

 GUIDを使ってランダムなパスワードを生成する方法の良いところは、実現するのも使用するのも簡単なことです。しかし出力される結果をコントロールできない上に、英数字(しかも文字はaからfまで)のパスワードしか生成することができません。セキュリティのガイドラインを適用するために、アルファベット以外の文字を何文字か使用したパスワードや、広い範囲の文字(アルファベット全部など)を使ったパスワードなどが必要になったとしても、対応することができません。また、何らかの理由で数字を使わないパスワードが必要になった場合や、パスワードの大文字と小文字を区別したくなった場合にも同じことが言えます(前述のGUIDを使った方法では6文字しか使えず、しかもすべて小文字です)。

 より堅牢な方法を実現するには、GeneratePassword(length, numberOfNonAlphanumericCharacters)というパスワードジェネレータを作ります。このパスワードジェネレータでは、ASP.NET 2.0のMembership APIに含まれている同名のメソッドと同等の機能を再現します(このメソッドは、ASP.NET 2.0を使っているのであればぜひ使いたいメソッドであり、パスワードの長さとアルファベット以外の文字の数を指定することができます)。さらに、このパスワードジェネレータは、強力な暗号化機能を持った乱数ジェネレータであるRNGCryptoServiceProviderクラスを使用しています。そのため、このアルゴリズムでは、以前に生成された乱数を基にこれから生成される乱数の予想を立てることは困難です。

 私と同じようにASP.NET 1.xの世界から抜け出せないのであれば、自作のGeneratePassword()メソッドを使わなければなりません。しかし、ASP.NET 2.0と同じものを開発する必要はありません。ASP.NET 2.0のコードを借用すればよいのです。それはReflectorを使えば簡単に実現できます。Membership.GeneratePassword(length, numberOfNonAlphanumericCharacters)のコードを次に示します。ライブデモもご覧ください。

’ VB.NET
Function GeneratePassword(ByVal length As Integer, _
        ByVal numberOfNonAlphanumericCharacters As Integer) As String
  ’Make sure length and numberOfNonAlphanumericCharacters are valid....
  ’... checks omitted for brevity ... see live demo for full code ...
  
  Do While True
    Dim i As Integer
    Dim nonANcount As Integer = 0
    Dim buffer1 As Byte() = New Byte(length  - 1) {}
    
    ’chPassword contains the password’s characters as it’s built up
    Dim chPassword As Char() = New Char(length  - 1) {}
    
    ’chPunctionations contains the list of
    ’legal non-alphanumeric characters
    Dim chPunctuations as Char() = _
      "!@@$%^^*()_-+=[{]};:>|./?".ToCharArray()

    ’Get a cryptographically strong series of bytes
    Dim rng as _
      New System.Security.Cryptography.RNGCryptoServiceProvider
    rng.GetBytes(buffer1)
        
    For i = 0 To length - 1
      ’Convert each byte into its representative character
      Dim rndChr As Integer = (buffer1(i) Mod 87)
      If (rndChr < 10) Then
        chPassword(i) = Convert.ToChar(Convert.ToUInt16(48 + rndChr))
      Else
        If (rndChr < 36) Then
          chPassword(i) = _
            Convert.ToChar(Convert.ToUInt16((65 + rndChr) - 10))
        Else
          If (rndChr < 62) Then
            chPassword(i) = _
              Convert.ToChar(Convert.ToUInt16((97 + rndChr) - 36))
          Else
            chPassword(i) = chPunctuations(rndChr - 62)
            nonANcount += 1
          End If
        End If
      End If
    Next
    
    If nonANcount < numberOfNonAlphanumericCharacters Then
      Dim rndNumber As New Random
      For i = 0 To (numberOfNonAlphanumericCharacters - nonANcount) - 1
        Dim passwordPos As Integer
        Do
          passwordPos = rndNumber.Next(0, length)
        Loop While Not Char.IsLetterOrDigit(chPassword(passwordPos))
        chPassword(passwordPos) = _
          chPunctuations(rndNumber.Next(0, chPunctuations.Length))
      Next
    End If
    
    Return New String(chPassword)
  Loop
End Function
 ここではGetPassword()メソッドに変更を加えて、エラーを起こす可能性のある英数字以外の文字(#&amp;)を除外しました。ASP.NET 2.0では、ランダムに生成されたパスワードがクロスサイトスクリプティング攻撃に悪用されないようにチェックしており、&lt;#、および&amp;をチェック対象にしています。このメソッドでは、こうしたチェックをしなくて済むように、単純にこれらの文字を除外しています。

まとめ

 この記事では、ASP.NETを使った2種類のランダムなパスワードの生成方法を取り上げました。1つ目の手法では、GUIDからハイフンを取り除いて最初のlength文字を取得しました。これは手早く簡単にランダムなパスワードを生成する方法です。しかし、使用可能な文字の種類がかなり限られている(aからf、および0から9)ので、複雑なことはできません。

 もっと強力で洗練されたランダムパスワードジェネレータが、ASP.NET 2.0のMembership.GeneratePassword()メソッドです。ASP.NET 2.0を使っているのであれば、このメソッドを使うのがよいでしょう。しかし、まだASP.NET 1.xを使っている場合に、GUIDを使った手法よりも強力なパスワードジェネレータが必要なのであれば、自分で作成する必要があります。そこでReflectorを使ってASP.NET 2.0のGeneratePassword()メソッドを「コピー」する方法を説明しました。

 ぜひ試してみてください。

著者紹介

Scott Mitchell(Scott Mitchell)
海外のインターネットコムアメリカ韓国ドイツトルコ
Copyright 2008 Jupitermedia Corporation All Rights Reserved.http://www.internet.com/