SecureStringクラスは、文字列を保持するStringクラスと似たクラスですが、SecureStringクラスに格納される文字列が自動的に暗号化される点でStringクラスとは異なります。 SecureStringクラスは、パスワードなどの文字列を格納するのに適しています。
SecureStringクラス
SecureStringクラスでは文字列が暗号化される点に加え、Disposeメソッドによって内容を破棄できる点でStringクラスと異なります。 Stringクラスではガベージコレクタによって破棄されるまでは文字列がメモリ上に残りますが、SecureStringクラスでは、Disposeメソッドを呼び出すことで不要になった時点で即座に破棄出来ます。 また、スレッドが中断されたりする場合などでも、確実に破棄されることがランタイムで保証されています(SecureStringクラスはCriticalFinalizerObjectクラスから派生しているため)。
SecureStringはStringからは生成することは出来ず、StringBuilderと似た操作で1文字ずつ追加する必要があります。 文字列の追加にはAppendCharメソッドやInsertAtメソッド、削除にはRemoveAtメソッドなどを使います。 変更の必要が無くなった時点でMakeReadOnlyメソッドを呼ぶことで、文字列の内容を読み取り専用にし、変更できないようにできます。
SecureStringは、ProcessStartInfo.Passwordプロパティなどで使われる他、.NET Framework 4からはNetworkCredential.SecurePasswordプロパティでも使用出来るようになっています。
SecureStringの使用例
SecureStringの使用例をNetworkCredentialを使って見てみます。 この例では、HTTPで認証が必要なページにアクセスし、その内容を表示します。 1度目のリクエストではユーザ名・パスワードを指定せずにアクセスし、HTTP Basic, Digest等による認証が必要だった場合(401レスポンスとなった場合)には、NetworkCredentialでユーザ名・パスワードを指定してから再度取得を試みます。
上記の例において、SecureStringに格納したパスワードが暗号化された状態であるのはリクエストが送信されるまでである点に注意してください。 リクエストがサーバに送信される時点で、SecureStringから暗号化が解除されたパスワードが取り出されます。 Digest認証では取り出されたパスワードがハッシュ化された上で送信されますが、Basic認証ではパスワードが平文で送信されます。
SecureStringはあくまでメモリ上の文字列を暗号化しておくためのものであり、通信経路上での文字列の暗号化には寄与しません。 したがって、上記の例のようにSecureStringが保持している文字列を通信経路を介して送受信する場合は、HTTPではなくHTTPSを使う、SslStreamクラスと組み合わせてSSL/TLSを使うなどにより通信経路の暗号化もあわせて行うようにする必要があります。
この例では、Console.ReadKeyメソッドを使うことにより、入力されたパスワードがコンソール上に表示されない(エコーバックしない)ようにしています。 実装の詳細、より適切な実装方法についてはエコーバックせずに文字列を入力する(Console.ReadKey)を参照してください。
Stringへの変換
StringBuilderとは異なり、SecureString.ToStringメソッドを呼び出してもSecureStringに格納されている文字列を取得することは出来ません。 SecureStringから文字列を取得するには、Marshalクラスのメソッドを使って一度メモリ上にコピーしてから、その内容をStringとして取得します。 次の表は、SecureStringから文字列を取り出すために使用できるMarshalクラスのメソッドの組み合わせです。
メモリ上への文字列のコピー (SecureStringTo*) |
ポインタから文字列への変換 (PtrToString*) |
コピーした文字列の開放 (ZeroFree*) |
---|---|---|
SecureStringToBSTR | PtrToStringBSTR | ZeroFreeBSTR |
SecureStringToCoTaskMemAnsi | PtrToStringAnsi | ZeroFreeCoTaskMemAnsi |
SecureStringToCoTaskMemUnicode | PtrToStringUni | ZeroFreeCoTaskMemUnicode |
SecureStringToGlobalAllocAnsi | PtrToStringAnsi | ZeroFreeGlobalAllocAnsi |
SecureStringToGlobalAllocUnicode | PtrToStringUni | ZeroFreeGlobalAllocUnicode |
なお、SecureStringTo*メソッドを呼び出して取得したポインタは、必ず対応するZeroFree*で開放する必要があります。 以下は、SecureStringに文字列を格納し、再びStringとして取得する例です。