今のところ私たちは(ここまで読んで理解できている読者の方は)サービスインストーラの作成
サービスが WCF でサーバーアプリとして動作すること
たとえばリモートパソコンの指定パスの2GBのファイルをStreamを介して無線LAN経由で6分ほどで取得するアプリなど
こうした通信技術を保持するプログラムを簡単に実現する能力を持っています。
ここまで示してきたリンク先を注意深く読んできた方はWCFのエンドポイントを複数用意できること
エンドポイントごとにABCでいうところのB:バインドを設定できること
バインドにはTCP, Named-Pipe, HTTP, HTTPSなどが選べることを知っているはずです。
(知らない人はこの先を読み進めても理解できません。)
今回はその複数エンドポイントの設定と、各種バインドで正常動作すること。
簡単なパフォーマンスの比較を行って、それぞれの使い分けのポイントを押さえたいと思います。
今までは暗号化も認証もしないで、ただアクセスしてきた相手へ情報を渡していました。
これがディフォルトでできるバインドは BasicHTTP のみで、ほかのバインドを試そうとすると機密性、認証、承認が確立された
基盤技術を用いたセキュリティ設定が求められます。
(明示的にセキュリティを切ることは可能です。)
もし、自宅の環境にてWindows認証機構を導入されているユーザーの方は、設定をWindowsにするだけで良いのですが
私の自宅環境では、そのような認証機構は構築していません。
そこで、今回は電子署名や相手認証の基盤技術である PKI を学び、これを利用した WCF のセキュリティ
というものを正しく理解し、私と同程度の初心者が設定できるようになるくらいの情報を羅列します。
興味ありましたら、お付き合いください。
まず PKI について学びます。
通信の脅威は次の四つ、盗聴、なりすまし、改ざん、否認拒否(犯人だが嘘をつく)です。
それぞれの対抗手段に暗号化、相手認証、メッセージ認証(電子署名)、電子署名が確立されました。
暗号化方法を共通化できる「鍵」を使った暗号化というものが PKI の基盤となる技術です。
鍵は通信内容からは特定できない仕組みとなっており、本人が公開しない限りは外部には漏れません。
これにより情報は鍵を持つ者にしか渡らないという認識に至ります。
鍵方式は大きく分けて2通り、共通鍵方式と公開・秘密鍵方式があります。
暗号化と複合化に同じ鍵を使うか、それぞれ別の鍵を使うかの違いです。
前者の場合、共通鍵を相手と自分だけが使えるように秘密にしなければなりません。
後者は暗号化用の鍵を公開できるので、秘密にするのは自分が持つ複合化用の鍵だけです。
比較して高速なのが前者、取り回しが良いのが後者です。
共通鍵方式のアルゴリズムは 1977 年に DES が採用されましたが、いつのころか 7万台のPCで22時間かけて解けるようになったので
2001年に別の新方式を募集して、主流アルゴリズムが切り替わりました。
(今のところ共通鍵方式のアルゴリズムは DES を含め AES や Camellia など、複数アルゴリズムから選べるようです。)
公開鍵方式は RSA が主流となっており、この RSA については次のページを参考に理解しました。
RSA を簡単に説明すると
公開鍵で平文(数値)を累乗して、共通の分母で割った時の余り(暗号化後の数値)を相手に送り
受け取り側は秘密鍵でその数値を累乗して、共通の分母で割ると、余りが元の数値に戻るというもの。
計算例にも示されているとおり、巨大な整数の素因数分解が暗号解読の手段ですが
整数の素因数分解について、例えば 11桁くらいならば一瞬で解けますが 256桁になると
現在の計算機パワーでは何100個のPCで数年間解読プログラムを回してもなかなか解けません。
こうした暗号技術に信頼をおいて、私達はとても大事なIDとパスワードを暗号化した形で公開しています。
計算例を見て気づいたと思いますが、秘密鍵方式で暗号化・復号化を行っていると
計算負荷が高くなり、パフォーマンスが出ません。パフォーマンス面では共通鍵方式が勝っているので
最初に公開鍵方式で共通鍵を交換して、以降共通鍵方式で通信し合えば
第三者が覗いても内容を知られずに済み、かつ高速に情報をやり取りできるようになります。
ハイブリッド方式と呼ばれています。
それでは具体的に私達が設定する項目を見ていきましょう。
ファイルの通信を行なうプログラムのバインドの部分をbasicHTTPからnetTCPに切り替えます。
また、マルチバインディングというものを設定してみたいと思います。
マルチバインディング…と言うかわかりませんが、エンドポイントを複数持つサービスを用意して
クライアントから片側のエンドポイントを使用して通信してみます。
成功しました。
以下成功時の設定ファイルです。
net.tcp バインディングの方法を示しましたが、アドレスの http → net.tcp の修正と
ベースとなるバインディングを basicHttp → netTcp に切り替えただけです。
net.tcp バインディングではディフォルトで Transport レベルのセキュリティが有効になっています。
ここに示した通り security mode="None" にして、平文通信にして通信を成功させてみてください。
はい、確認したいことが一つ片付きました。
ではいよいよセキュリティを有効にして暗号化した情報をやりとりしてみたいと思います。
証明書とは X.509 証明書のことです。これは広く使用されている資格情報です。
PKI 技術でいう所の公開鍵が入っています。
Transport セキュリティはサービス認証、クライアント認証、Point To Point での暗号化が行え
高速な上に、ストリーミングが行えるという利点もあります。
ただし Point To Point の暗号化のため中継局にて内容が筒抜けになってしまうわけで安全とは言えません。
中継局にも秘密にしたまま通信を行える、メッセージセキュリティを選択したいところですが
低速かつ、ストリーミング通信が行えないという点で選択できないケースがあったりします。
というわけで、まず証明書を利用したTransportセキュリティを実現して動作確認までしてみたいと思います。
まずは現在平文通信しているnet.tcp通信の設定をセキュリティが働くように編集してみましょう。
サーバーとクライアントの両方で security mode="Transport" としてください。
さて、これだけでは認証に成功しません。(Windows認証機構が働いていれば成功します。)
次に証明書を利用するので証明書利用であることを設定します。
そして、どこに証明書があるか指定します。
LocalMachine の My の所にクライアント用に SimplestarGame_Test_Client_CA を
サーバ用の SimplestarGame_Test_Ext_CA を指定しています。
重要なのが8行目の revocationMode="NoCheck" です。
ディフォルトのオンライン認証にしてしまうと私が作った認証局は信頼されていないため通信ができなくなります。
これからテスト用に(お金を払わずに)自分で認証局を作成するので、忘れずにオンライン認証を外しておきましょう。
上記の設定はWCF構成の編集より[詳細設定]→[サービス動作]で作成可能です。
作ったサービス動作は次のように、サービス自体にひも付けてください。(1行目)
ひとまず設定は完了したので、サーバーアプリを起動してみます。
すると例外を投げて終了しました。
例外の内容は次のとおり「SimplestarGame_Test_Client_CA 証明書が見つかりませんでした。」
それもそのはず、作ってませんし登録もしていませんからね。
では証明書を作りましょう。
まずはルート証明書を作成します。
証明書作成には Makecert.exe というツールを使うのですが、次の場所に存在します。(VisualStudio2010の場合)
C:\Program Files\Microsoft Visual Studio 10.0\VC
使い方は次のページから学べます。
さて、作成方法も次のページから手に入れる事ができます。
上記のドキュメントリンクを参考に実際にルート証明書を作ってみます。
パスワードの入力が求められました。
パスワードを設定して、秘密鍵を守ります。
ルート証明書の作成に成功したら、クライアントとサーバーのPCにて「信頼されたルート証明機関」に登録します。
登録方法は次のページに示されています。
方法 : 署名の検証に使用する証明機関の証明書チェーンを指定する (WCF)
どこも同じようなことが書かれていますが mmc コマンドで起動したアプリにて[スナップインの追加]より[証明書]を選択
ローカルマシンの「信頼されたルート証明機関」の「証明書」に .cer ファイルをインポートすることで登録完了です。
続いて、サーバー側に持たせる証明書を作ります。
次のコマンドを「管理者権限」で実行します。(なぜ権限を上げる必要があるかですが、秘密鍵付きで mmc に登録するためです。)
パスワードが求められましたら、先程ルート証明書の作成で設定したパスワードを入力します。
サーバー側のマシンで mmc を開き、[証明書(ローカルコンピューター)]→[個人]→[証明書]を確認してください。
SimplestarGame_Test_Ext_CA 証明書が秘密キーを持っている状態(アイコンに鍵マーク付き)で登録されていれば成功です。
残るはクライアントの証明書ですね。
今度はクライアント側のPCで作業します。
すでにサーバー側のPCで行ったとおりの手順で「信頼されたルート証明機関」にルート証明書が登録されているはずですので
次のコマンドを「管理者権限」で実行するだけです。
パスワードが求められましたら、ルート証明書の作成で設定したパスワードを入力します。
クライアント側のマシンで mmc を開き、[証明書(ローカルコンピューター)]→[個人]→[証明書]を確認してください。
SimplestarGame_Test_Client_CA 証明書が秘密キーを持っている状態(アイコンに鍵マーク付き)で登録されていれば成功です。
はい、ではお互いのPCで公開鍵を交換します。
すでに書き出されているそれぞれの証明書の .cer ファイルを mmc を開き
[証明書(ローカルコンピューター)]→[個人]→[証明書]に登録するでも良いですし
もっと確実に、それぞれの証明書から mmc を介してエクスポートしたファイルを同じように
mmc を開き、[証明書(ローカルコンピューター)]→[個人]→[証明書]に登録しても構いません。
はい、これでお互いに秘密鍵と公開鍵を持つ形で証明書を登録できました。
WCFのサーバーアプリの設定のとおり、サブジェクト名で探せば証明書が見つかるはずです。
先程証明書がなくて起動に失敗したサーバーアプリを立ち上げます。
よし!まずはサーバー側の準備が完了です。
あとは同様に Transport セキュリティを有効にしたクライアントの設定を作ってクライアントを起動してみます。
セキュリティ設定で大切な部分をハイライトしました。
クライアントとサービスにそれぞれ正しい証明書を指定するのはもちろん
13行目、ここでもオンライン認証を避けて、無理やり自分の証明機関を信頼させます。
またIDの比較というものが行われるため、36行目にて DNS 設定を行っています。
悪意あるサーバーに情報を送らないようにするため
証明書のサブジェクト名が予想したサーバーのものと一致しない場合
情報を相手に送らない仕組みです。
さて、これでサーバーとクライアント間で証明書を利用した Transport セキュリティを有効にしたまま
暗号化通信しながらストリーミングを行えるはずです。
試験してみます。
やりました!動きました。
セキュリティを有効にしたまま 2GB ファイルの転送が 6分ほどで完了しました。
目的達成です!
もっと強固なセキュリティを使ってみたいと思います。
中継局にも秘密にしたまま、相手と自分のPCだけで秘密の通信を行ってみます。
ハイライトした所だけ変えます。
残念ながらこのままではサーバーアプリは例外を吐いて死にます。
ストリームタイプでバインドしていますが、こんなバインドではダメだと言ってきました。
TransferMode を Buffered に変更します。
今度はどうでしょう。
ダメでした、バッファサイズ考えろとのことです。
整数値の範囲に直します。
やっとサーバーアプリを起動できました。
同様の設定変更をクライアント側の設定に加えて試験してみます。
試験成功です!バッファサイズ内?であればファイルデータの通信に成功しました。
(16MBの40秒の動画の送信に成功)
当然ですが 2GBファイルの通信を行おうとするとクライアント側が例外を吐いて死にます。
確認ですがストリーム通信ができないだけで、インタフェースに Stream を付ける分には大丈夫です。
つまり下記の関数を使ってリモートPCからファイルを取得することが可能です。
調査目的の大部分を消化しました。
さて、ユーザー認証を証明書にするにはクライアントが秘密鍵を持つようにして
証明書の作成を行わなければなりません。
ユーザー認証だけユーザー名とパスワードにすることも WCF で簡単に構築できます。
次回にユーザー名とパスワードによるクライアント認証を示したいと思います。
興味ある方は NEXT へどうぞ。
2014/01/19 最終更新