しばやん雑記

Azure Serverless とメイドさんが大好きなフリーランスのプログラマーのブログ

ASP.NET と MachineKey の関係をまとめてみた

先日、盛大に罠にはまったので MachineKey について改めてまとめておきます。

そもそも MachineKey とは何ぞやと言う話ですが、フォーム認証やビューステートでの検証と暗号化で使われるキーです。ASP.NET のランタイムが生成する認証用のクッキーやビューステートは、この MachineKey を使って改ざん対策と暗号化を行うことが可能です。

machineKey 要素 (ASP.NET 設定スキーマ) | Microsoft Docs
MachineKeySection クラス (System.Web.Configuration) | Microsoft Docs

MachineKey と言う名前なのでサーバごとに一意な値が生成されるかと思いがちですが、実際にはそうではありません。

Web.config で MachineKey を明示的に指定していない場合には自動生成されるので、何らかのタイミングで値が変わることがありますし、Windows Azure などのクラウドサービスを使う場合にはスケールアウトなどでサーバの台数を増やしたときに、インスタンス毎に別々の MachineKey が使われてしまうという問題もあります。

稼働途中で MachineKey が変わってしまうと、フォーム認証やビューステートの検証が失敗してしまうので、ログイン状態やページの状態が破棄されてしまう訳です。なので、明示的に MachineKey を指定しておくことが重要になります。

思ったよりいろいろと使われていて重要な MachineKey ですが、簡単に作れる Web サービスが公開されているので利用するのがおすすめです。

aspnetresources.com

「Generate Key」ボタンをクリックするだけで検証用と暗号化用のキーを生成してくれます。Web.config にそのまま貼り付け可能な状態で生成されるので、めちゃくちゃ簡単ですね。ちなみにこのサービスで MachineKey を作成すると、改ざんの検出には HMACSHA1 が、暗号化には AES が使われるようになっています。

ここからはフォーム認証とビューステートについて個別に見ていきます。

フォーム認証に関しては Web.config で検証と暗号化を行うかを設定することが可能ですが、デフォルトでは両方行うようになっているので特に理由が無い限りは変更する必要はありません。

<authentication mode="Forms">
  <forms protection="None" />
</authentication>

上記のように forms 要素の protection 属性の値を None にすると検証と暗号化の両方が無効になります。ちなみに protection 属性には以下の値が指定可能です。

  • All
    • 検証と暗号化の両方を有効にする
  • Encryption
    • 暗号化のみ有効にする
  • Validation
    • 検証のみ有効にする
  • None
    • 全て無効にする

ビューステートに関してはデフォルトでは検証のみが有効になっていて、暗号化までは行われていないのですが、そもそも暗号化が必要なデータをビューステートに持たせることが間違っているので、改ざん対策のみ有効で問題ないですね。

機密性の高い情報はサーバ側で持たせるようにしましょう。

ちなみに MachineKey を使った検証と暗号化は .NET 4.5 から追加された MachineKey クラスの Protect/Unprotect メソッドを使って行うことが出来ます。

var buffer = Encoding.UTF8.GetBytes("hauhau");

// 暗号化
var protectedData = MachineKey.Protect(buffer, "foo");

// 復号化
var unprotectedData = MachineKey.Unprotect(protectedData, "foo");

MachineKey クラス (System.Web.Security) | Microsoft Docs

この場合に暗号化したときのキーが異なる場合や、暗号化後のデータが改ざんされていた場合には CryptographicException が投げられます。

お手軽に改ざんの検出と暗号化を行えるのは便利ですね。