間もなくリリースされる.NET 5では、互換性に関わる重大な変更(breaking change)が多数導入されている。多くは特殊なケースに関わるものや、従来の動作が不適切であったものだが、開発者を驚かせるようなものもいくつかある。一連のニュースの初回として、今回の記事ではBase Class Libraryに注目する。
.NETバージョン情報
愚行に思えるかも知れないが、多くの開発者が、バージョンを数値ではなく文字列表現で判断するという悪癖を持っている。これは悪名高い"Windows 9"の物語と関係がある。MicrosoftがWindows 8からWindows 10にスキップしたのは、Windows 95/98を検索するアプリケーションに問題が発生することを避けるためだったのだ。
.NETでは、開発者に選択の余地はなかった。奇妙な番号付けスキームも一因となって、開発者は、".NET Framework #.#"または".NET Core #.#"を検索するという、文字列表現に依存せざるを得なかったのだ。
.NET 5では、呼称がシンプルな".NET #.#"になる。ランタイムバージョンの検出に依存するアプリケーションやライブラリは、アップデートが必要だ。
OSバージョン情報
従来は、Environment.OSVersionがアプリケーションに嘘をつくことがあった。本当のOSバージョンを返す代わりに、アプリケーションのWindows互換性モード設定に基づいて、エミューレートされたOSを返していたのだ。Mircrosoftの説明によると、
このプロパティのユーザは、オペレーティングシステムの実際のバージョンが返されることを期待しています。大部分の.NETアプリケーションは、サポート対象バージョンをアプリケーションマニフェストに記述していません。そのため、dotnetホストからデフォルトのサポート対象バージョンを受け取ることになります。その結果、互換性シム(compatibility shim)がアプリケーション実行にほとんど意味を持たないものになっているのです。Windowsの新しいバージョンがリリースされて、古いdotnetホストが引き続き使用される場合、これらのアプリは正しくないOSバージョンを取得する可能性があります。実際のバージョンに回帰することで、このAPIに対する開発者の期待に、より一致するようになります。
バンドルアプリケーションのファイル配置
アプリケーションが依存関係とともに単一ファイルにバンドルされている場合、一部のReflection APIの動作が不明確なものになる。これまでのバンドルアプリケーションでは、依存関係を一時的なロケーションに取り出していたため、Reflection呼び出しではこれを参照していた。.NET 5では、依存関係はメモリから直接ロードされるため、参照する物理的アセンブリは存在しなくなる。このため、以下のAPIは変更する必要があった。新たな動作は次のようになる。
Assembly.Location
: バンドルアセンブリとして空文字列を返すAssembly.CodeBase
: バンドルアセンブリに対しては例外をスローするAssembly.GetFile(String)
: バンドルアセンブリに対しては例外をスローするEnvironment.GetCommandLineArgs()[0]
: 値はホスト実行ファイルの名前になるAppContext.BaseDirectory
: 値はホスト実行ファイルを含むディレクトリになる
ログ
以下のConsoleLoggerOptions
が"obsolete"とマークされた。これらはConsoleFormatterOptions
のいくつかのサブクラスで置き換えられることになる。
ConsoleLoggerOptions.DisableColors
ConsoleLoggerOptions.IncludeScopes
ConsoleLoggerOptions.TimestampFormat
ConsoleLoggerOptions.UseUtcTimestamp
ConsoleLoggerOptions.Format
BinaryFormatterシリアライゼーションのブロック
BinaryFormatterは、.NETのシリアライゼーションライブラリに当初から存在するクラスである。同時に提供されたXMLベースのSoapFormatter
よりも高速かつコンパクトであることが、その存在意義だった。
残念ながらこのクラスは、いくつかの問題を抱えている。その最たるものが、安全に使用することができない、という点だ。MicrosoftのBinaryFormatter
セキュリティガイドには、次のような警告がある。
BinaryFormatter.Deserialize
メソッドは、信頼できない入力に対して、決して安全ではありません。この記事で後述される代替策のひとつを検討するように、強く推奨します。
さらに、
BinaryFormatter
の利用者には、個々のアプリにおいてリスクの判断を実施するようにお勧めします。BinaryFormatter
の使用の可否を判断するのは、利用者のみの責任です。利用者は、BinaryFormatter
の使用に関するセキュリティ、技術、評価、法律、規制要件に関するリスクを評価する必要があります。
Microsoftが安全でないと考えるシリアライゼーションライブラリはこれだけではない。以下のものは、危険性は高くないものの、無制限にポリモーフィックなデシリアライゼーション(deserialization)が懸念されるため、使用は回避するべきだ。
SoapFormatter
LosFormatter
NetDataContractSerializer
ObjectStateFormatter
.NET 5では、BinaryFormatter
は、ASP.NETについてはデフォルトで無効になっており、その他のアプリケーションフレームワークではコンパイル時に警告が生成される。WebサイトでBinaryFormatter
を使用する必要がある場合は、EnableUnsafeBinaryFormatterSerialization
フラグを使って再度有効にすることができる。
UTF-7のブロック
もうひとつブロックされたテクノロジはUTF-7である。このフォーマットは、HTML5など多くの標準ですでに使用禁止(forbidden)になっている。これが禁止されたのは、アプリの一部でデータがUTF-8フォーマットであるように見せかけて、他の部分ではUTF-7として正しく処理することによって、アプリケーション内に悪意のある文字列を潜ませることが簡単にできるためだ。
Wikipediaに詳しい説明がある。
UTF-7では、同じソース文字列に対して複数の表現が可能です。特にASCII文字列は、Unicodeブロックの一部として表現することができます。そのため、標準的なASCIIベースのエスケーププロセスや検証プロセスが使用されている場合、Unicodeブロックを使った悪意のある文字列がそれらをすり抜けて、後でUTF-7として解釈されることがあり得ます。この問題を軽減するためには、検証処理の前にデコードを実施して、UTF-7の自動検出を行わないようにしなければなりません。
Internet Explorerの古いバージョンは、ページをUTF-7として解釈するようにだまされる可能性があります。< と > をUTF-7の +ADw- と +AD4- にエンコードすることが可能なことから、これがクロスサイトスクリプティングに利用される場合があります。ほとんどのバリデータは、これらを単純なテキストとして通してしまうのです。
レガシデータの処理が必要であれば、EnableUnsafeUTF7Encoding
フラグを使用して処理可能にすることもできる。
Microsoft.DotNet.PlatformAbstractionsパッケージの廃止
技術的な変更ではないが、開発者に対して、オペレーティングシステムに関する情報取得にMicrosoft.DotNet.PlatformAbstractionsを使用しないように、強く勧告されている。このライブラリには今後アップデートの予定はないため、将来的には不正確なものになると思われる。
以下に挙げたのは、廃止されるメソッドとその代替である。
ApplicationEnvironment.ApplicationBasePath => AppContext.BaseDirectory
HashCodeCombiner => System.HashCode
RuntimeEnvironment.GetRuntimeIdentifier => RuntimeInformation.RuntimeIdentifier
RuntimeEnvironment.OperatingSystemPlatform => RuntimeInformation.IsOSPlatform(OSPlatform)
RuntimeEnvironment.RuntimeArchitecture => RuntimeInformation.ProcessArchitecture
RuntimeEnvironment.OperatingSystem => RuntimeInformation.OSDescription
RuntimeEnvironment.OperatingSystemVersion => RuntimeInformation.OSDescription and Environment.OSVersion
本シリーズの第2部では、.NETの歴史的なテクノロジのいくつかに関わる、重大な変更について説明する予定である。