ASP.NETを使ってランダムなパスワードを生成するはじめに私は現在、あるコンサルティング案件で、ユーザーアカウントを使用するWebサイトに携わっています。このサイトでは、ユーザーアカウントの作成方法が2種類あります。1つはユーザー自身で作成する方法で、この場合、ユーザーは電子メールアドレスとパスワードを入力します。もう1つはユーザーの上司が作成する方法で、この場合、上司はユーザーの電子メールアドレスだけを入力します。すると、サイトがユーザー用にランダムなパスワードを生成し、そのパスワードをユーザーに電子メールで通知します。ユーザーは最初のログイン時に、このランダムなパスワードを変更しなければなりません。 この方式を実現するためには、ランダムなパスワードを生成するプログラムを書くことが必要でした。そこで、4Guysで"random password"という言葉を検索してみました。残念ながら、ランダムなパスワードの生成について4Guysで見つかった記事はクラシックASP時代の古いものばかりだったので、自分でASP.NETのランダムパスワードジェネレータを書く必要がありました。この必要性については「ASP.NET 2.0’s new Membership API」で取り上げられており、実際のところ、ASP.NET 2.0では この記事では、ASP.NET用のランダムパスワードジェネレータについて紹介します。ランダムなパスワードを生成するにはいろいろなテクニックがあり、これらのテクニックについてソースコードを示しながら解説します。それでは始めましょう。 GUIDを使った手っ取り早いランダムなパスワードの生成 ASP.NETを使ってランダムなパスワードを生成する最も簡単な方法は、GUIDの一部を取得することです。GUIDとはGlobally Unique ID(世界で唯一のID)のことで、1つのメソッド呼び出しですぐに生成できる128ビットの数値です。これを使えば、ランダムなパスワードとして使える16進数の文字列を生成することができます。GUIDを新たに生成するには、 ’ 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文字を取得します。このテクニックを一般の用途に使えるように、 ’ 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); 以下は Random password of length 5:ce7e9 Random password of length 10: 578562009e Random password of length 15: 7b0fc1bc9ea9486 さらに強力なランダムパスワードジェネレータGUIDを使ってランダムなパスワードを生成する方法の良いところは、実現するのも使用するのも簡単なことです。しかし出力される結果をコントロールできない上に、英数字(しかも文字はaからfまで)のパスワードしか生成することができません。セキュリティのガイドラインを適用するために、アルファベット以外の文字を何文字か使用したパスワードや、広い範囲の文字(アルファベット全部など)を使ったパスワードなどが必要になったとしても、対応することができません。また、何らかの理由で数字を使わないパスワードが必要になった場合や、パスワードの大文字と小文字を区別したくなった場合にも同じことが言えます(前述のGUIDを使った方法では6文字しか使えず、しかもすべて小文字です)。 より堅牢な方法を実現するには、 私と同じようにASP.NET 1.xの世界から抜け出せないのであれば、自作の ’ 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()メソッドに変更を加えて、エラーを起こす可能性のある英数字以外の文字(#と&)を除外しました。ASP.NET 2.0では、ランダムに生成されたパスワードがクロスサイトスクリプティング攻撃に悪用されないようにチェックしており、<、#、および&をチェック対象にしています。このメソッドでは、こうしたチェックをしなくて済むように、単純にこれらの文字を除外しています。まとめ この記事では、ASP.NETを使った2種類のランダムなパスワードの生成方法を取り上げました。1つ目の手法では、GUIDからハイフンを取り除いて最初の もっと強力で洗練されたランダムパスワードジェネレータが、ASP.NET 2.0の ぜひ試してみてください。 著者紹介Scott Mitchell(Scott Mitchell)
![]()
|