読者です 読者をやめる 読者になる 読者になる

Windows上で電子署名されたロードモジュールを実行するとなーんか遅い?という話

仕事であった話し。

なんか、今まで普通に動いていたプログラムが、最近導入した先だとなぜか遅い。どうもそのプログラムはサードパーティーの画像処理の部品を使っているようなんだけど、なんか関係があるのかな?

なんて話があって、ちょっと調査した。

最初は何の手がかりもなかったので原因の再現から。ラッキーな事に再現性は100%だったので、実際に見せてもらってどの程度の遅さなのかを計測。なんと、フォームのロードに20秒とかかかっている。これは誰が見ても「遅い」と感じる動き。で、一度フォームがロードされてしまうと、そのあとは普通。

とりあえず、タスクマネージャで見た限り、メモリが不足していたり、CPUが回っていたりする様子はない。ディスクのアクセスランプを見ても、ゴリゴリ回っている様子もない。ということで、Wiresharkで通信パケットを見てみた。

すると、件のサードパーティー製の部品をファイルサーバからロードした後に、なぜかcrl.verisign.comのDNSクエリが発行されている。

実行環境は、完全に外界から遮断されたネットワークなので、そんなところには届かない。

で、こんなDNSクエリが何発も出てから、他の部品のロードが行われる。この間、約15秒程度。遅い原因はどうやらこれらしい。

どーゆー理由でダメなのかはこれだけだと知識不足でわからなかったけど、verisign.comを調べているので、なにか電子署名とか電子証明書とかそーゆー系の何かじゃないか?ということで、部品のファイルのプロパティを確認すると、電子署名されたロードモジュールでしたよと。ついでに言うと、その署名の有効期限は切れていた。

まあ、電子署名されているロードモジュールがあると、署名した認証機関に何かをしに行くらしいという事はわかった。で、どうすりゃフォームのロードに20秒もかからないようにできるのか?という答えがこの時点ではさっぱりだった。最初はDNSがクエリの結果を返すまでに時間がかかっていたので、ここを「とどかねーよ!」(CV.相沢舞)と即答させれば速くなるんじゃね?とか思って、hostsにあり得ないIPとかを登録したんだけど、ダメで。しょーがないんで、あれこれと検索して出てきた答えがこれ。

.NET CLRが署名されたアセンブリをロードし、CLR発行元にアクセスできなかった場合、アセンブリの署名を確認できなかったという情報を記録します。したがってアセンブリはロードされますが、デジタル署名されていないものとして取り扱われます。WindowsがCRLをダウンロードできない場合には、15秒のタイムアウトになるまで再取得しようとします。よって.NETアセンブリの遅延はWindowsがCRLできずにタイムアウトになるまで15秒間ダウンロードし続けることが原因です。これは仕様通りの動作です。

Measurement Studio .NETアセンブリが実行時のロードに10秒以上かかる - National Instruments
なんと、ローダーの仕様! そーゆー事か! で、こいつをなんとかする方法も書いてあった。

コンピュータごとの回避策

コンピュータごとの回避策として、マイクロソフト社はInternet Explorerの設定でCRLチェックを無効にすることを勧めています。Internet ExplorerでCRLチェックを無効にするには、以下の手順を行います。

スタート » コントロールパネルを選択します。
インターネット オプションをダブルクリックします。
詳細設定タブを選択します。
セキュリティの項目で発行元証明書の取り消しを確認するのチェックを外します。
インターネットオプションでCRLチェックを無効にしても、このチェックは動作しないため、セキュリティ上の危険に晒されることはありません。これは、ネットワーク設定ではWindowsがCRLにアクセスさせないからです。

さらに、プログラム的にCRL検証を設定することができます。発行元証明書の取り消しを確認するのチェックを外すと、レジストリで設定が変更されています。CRL検証を無効にするには、HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\WinTrust\Trust Providers\Software Publishing\State from 0x00023c00を0x00023e00に設定します。CRL検証を再度有効にするには、Stateキーを0x00023c00に戻します。

アプリケーションごとの回避策

アプリケーションごとにこの問題を回避するには以下の手順を行います。

.NET Framwork 2.0 SP1以降を使用するか要求されるMicrosoft Hotfixをインストールします。
回避策を適用する各アプリケーションに対してアプリケーション構成ファイルを作成します。
アプリケーション構成設定でgeneratePublisherEvidenceをFalseに設定します。
アプリケーション構成設定のgeneratePublisherEvidenceについては、Microsoft Knowledge Base 936707を参照してください。

私の環境では、「アプリケーションごとの回避策」しかうまくいきませんでした。でも、この記述をconfigファイルに追加したら、署名のチェックは走らなくなったようで、スパっとフォームが表示されるようになった。

ということで、一つの事例の報告。こーゆーのでハマってる人いないのかな?