【入門編】VB.NETにおけるSecureStringの正しい使い方とメモリ保護:平文パスワードを保持しない安全な認証情報管理 – Visual Basic (VB / VB.NET)解析バイブル

スポンサーリンク

こんにちは!日々の開発、本当にお疲れ様です。
マクロの記録やなんとなく動くコードを卒業し、「よりセキュアでプロフェッショナルなシステムを作りたい!」そう思ってこのページに辿り着いたあなたへ。素晴らしいステップアップですね。

今回は、VB.NETでの開発において避けて通れない、しかし多くのプログラマーが見過ごしがちな「パスワードや機密情報のメモリ保護」について、世界最高峰のアーキテクト視点から優しく、深く、分かりやすく解説します。

ここをクリアすれば、あなたの書くコードの安全性は一段と跳ね上がります。一緒にバッチリマスターしていきましょう!

—

1. なぜ「普通の文字列(String)」でパスワードを扱うと危ないのか?

データベースに接続するとき、あるいは外部APIを叩くとき、私たちはよくこんなコードを書きがちですよね。

.net
‘ 【危険な例】普通のString型でパスワードを保持
Dim password As String = “P@ssword123”

一見、何の問題もないように見えます。しかし、セキュリティの現場やアーキテクトの視点から見ると、これは「玄関の鍵を開けっぱなしにして寝るようなもの」です。

.NETのString型が持つ「残酷な宿命」

VB.NETの `String` 型は非常に便利ですが、「イミュータブル(不変)」という性質を持っています。つまり、メモリ上で一度作られた文字列は、変更することができません。

さらに恐ろしいことに、
1. ガベージコレクタ(GC)がメモリを回収するまでの間、平文(暗号化されていない状態)のままメモリ上のあちこちに残り続ける。
2. タスクマネージャーのダンプ採取や、メモリ解析ツールを使うことで、悪意ある第三者にパスワードが丸見えの状態で読み取られてしまう。

本番環境や企業向けシステムにおいて、この脆弱性は致命傷になり得ます。そこで登場するのが、今回主役である `SecureString` です。

—

2. SecureStringとは?:メモリの金庫番

`System.Security.SecureString` クラスは、一言で言うと「メモリ上で暗号化され、不要になったら即座に消去できる文字列の金庫」です。

SecureStringの3大特徴

1. メモリ上で暗号化される: 保持している文字データは、Windowsの暗号化APIを使ってメモリ上で保護されます。
2. String型に変換しない: 内部のデータは常に隠蔽されており、簡単に `.Text` のようなプロパティで取り出せません。
3. 明示的な破棄(IDisposable): 使い終わったら、メモリ上から綺麗さっぱり消し去ることができます。

—

3. 【実践】VB.NETでの正しいSecureStringの扱い方

それでは、実際にコードを書いてその使い方を見ていきましょう。
「コンソールからパスワードを安全に入力し、それを安全に保持する」一連の流れを実装します。

.net
Imports System
Imports System.Security

Module SecureStringSample

Sub Main()
‘ 1. 安全なSecureStringインスタンスを生成する
‘ Usingブロックを使うことで、処理が終わった瞬間に確実にメモリから消去(Dispose)させます
Using securePass As SecureString = GetPasswordFromUser()

Console.WriteLine(Environment.NewLine & “— パスワードの取得と保護に成功しました —“)

‘ ここでデータベース接続や認証処理を行う
Authenticate(securePass)

End Using ‘ ここを抜けた瞬間、メモリ上のパスワードは完全に破壊・消去されます

Console.WriteLine(“パスワードはメモリから安全に破棄されました。”)
Console.ReadKey()
End Sub

‘ ユーザーからパスワードを安全に入力してもらうメソッド
Private Function GetPasswordFromUser() As SecureString
Dim securePassword As New SecureString()

Console.Write(“パスワードを入力してください: “)

Do
Dim keyInfo As ConsoleKeyInfo = Console.ReadKey(intercept:=True) ‘ 入力文字を画面に隠す

‘ Enterキーが押されたら入力終了
If keyInfo.Key = ConsoleKey.Enter Then
Exit Do
End If

‘ バックスペースが押された場合の処理(簡易版)
If keyInfo.Key = ConsoleKey.Backspace Then
‘ ※実際の厳密な実装では文字削除のハンドリングが必要ですが、今回は割愛します
Continue Do
End If

‘ 入力された一文字を、その場でSecureStringに追加(メモリ上で即座に暗号化される)
securePassword.AppendChar(keyInfo.KeyChar)

Console.Write(“”) ‘ 画面にはアスタリスクを表示
Loop

‘ 外部から改変されないように、読み取り専用(ReadOnly)の状態にロックする
securePassword.MakeReadOnly()

Return securePassword
End Function

‘ 認証処理の模擬(SecureStringを受け取る)
Private Sub Authenticate(ByVal pass As SecureString)
‘ 注意:古いAPIや一部のライブラリではString型を要求することがあります。
// その場合の安全な変換方法は後述します。
Console.WriteLine(Environment.NewLine & “認証システムへ接続中…”)
End Sub

End Module

コードのここがポイント!

  • `Console.ReadKey(intercept:=True)`: パスワード入力時によくある、入力した文字が画面に「“」として表示される(あるいは完全に見えない)ようにする仕組みです。これによって、肩越しに覗き見られるリスク(ショルダーハッキング)を防ぎます。
  • `MakeReadOnly()`: パスワードの文字入力が終わったら、これ以上変更されないように「読み取り専用」にロックします。セキュリティを高めるための必須作法です。
  • `Using` ブロック: VB.NETの強力な武器です。スコープを抜けた瞬間に `Dispose()` が呼ばれ、メモリ領域がゼロクリアされます。

—

4. 陥りやすい罠とエラー:古いAPIとのジレンマ

「さあ、SecureStringを使ったぞ!」……しかし、ここで多くの開発者が壁にぶつかります。
世の中の多くのデータベース接続ライブラリ(例えば、古いADO.NETの部品など)やサードパーティ製APIは、未だに以下のように普通の `String` 型でパスワードを要求してきます。

.net
‘ 外部ライブラリがこういうメソッドを要求する場合、どうする?
‘ Dim connString As String = “User ID=admin;Password=” & normalString

「結局 `String` に戻すなら、最初から `String` でいいじゃないか!」と思ってしまいがちですが、ここに最大の落とし穴があります。

🚨 絶対やってはいけないアンチパターン

.net
‘ 【絶対NG】Marshalを使ってStringに戻す(平文がメモリに残る)
Dim plainText As String = System.Runtime.InteropServices.Marshal.PtrToStringAuto(
System.Runtime.InteropServices.Marshal.SecureStringToBSTR(securePass)
)
‘ これをやると、SecureStringで頑張って守っていた意味が完全に消え去ります!

💡 正しい解決アプローチ

現代の.NET(.NET Core / .NET 5以降、および最新のVB.NET環境)では、SqlConnectionなどの主要なクラスが `System.Net.NetworkCredential` などを経由して安全にSecureStringを受け取れるようになっています。

どうしても平文に変換しなければならない場合は、「使用するその瞬間に変換し、使い終わったら直ちにメモリを上書き・解放する(ゼロ化する)」という細心の注意が必要です。

—

5. まとめ:プロフェッショナルへの第一歩

お疲れ様でした!今回はVB.NETにおける `SecureString` を使った堅牢なメモリ保護について解説しました。

  • 普通の `String` 型はメモリ上に平文が残り続けるため、パスワード用途には危険。
  • `SecureString` を使えば、メモリ上で暗号化され、安全に保持できる。
  • `Using` ブロックや `MakeReadOnly()` を組み合わせて、ライフサイクルを完全にコントロールする。

セキュリティ意識の高いコードを書けるエンジニアは、現場で圧倒的に重宝されます。「動けばいい」の código(コード)から、「安全で美しい」アーキテクチャへ。

ここをクリアしたあなたなら、もう立派なプロフェッショナルエンジニアの仲間入りです。
次の開発現場でも、ぜひこの知見を活かしてセキュアなシステムを作り上げてくださいね!応援しています!

タイトルとURLをコピーしました