JDBな人生  専門的なことから日常的なことまで~ まぁ自由きままに書いていきます。
2017年10月 / 09月<< 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 >>11月

アクセスランキング

[ジャンルランキング]
コンピュータ
304位
アクセスランキングを見る>>

[サブジャンルランキング]
プログラミング
35位
アクセスランキングを見る>>

クライアント認証の有効範囲

久々に技術系の記事を書こうと思います。
先日、管理しているWEBサイトの一つに、管理者用のコンテンツへのアクセス制限を目的として、クライアント認証を導入しました。

通常、phpMyAdminのような管理画面は、外部に公開する必要はありません。その場合、ローカルネットワーク内からのみアクセスを許可のうえ、VPNで接続するという形態をとるのが一般的かと思いますが、VPNが未設定のときにはそこから始める必要があります。
今回がその「未設定の状況」で、さすがにVPNの設定から行うのは手間がかかりすぎるということで、クライアント認証の導入という形で済ませることになったわけです。
あえてOSIモデルでいえば、ネットワーク層での制限ではなく、セッション層とアプリケーション層での制限という形ですね。

CAの構築・クライアント証明書の発行・署名等は今回の記事の趣旨から外れるので省略します。

さて、通常の設定だと以下のようになるはずです。

server {
(中略)
        ssl on;
        ssl_certificate (CERT)
        ssl_certificate_key (KEY)

        ssl_verify_client    on;
        ssl_client_certificate (CERT)
        ssl_verify_depth    1;
}


しかし、この記述のように、サーバ証明書が既に導入済みで、特定のディレクトリに関してだけクライアント認証「も」導入したい、というケースがあります。そこで「もし一部のディレクトリだけクライアント認証を設定できたら…」と考えると、次のような記述になるはずです。

server {
(中略)
        ssl on;
        ssl_certificate (CERT)
        ssl_certificate_key (KEY)

        location /(LOCATION) {
            ssl_verify_client    on;
            ssl_client_certificate (CERT)
            ssl_verify_depth    1;
        }
}


まあ書き方からお察しの通り、この設定では動きません。(お恥ずかしながら試してしまいました)
冷静に考えればすぐわかることですが、この記事では改めて確認をしてみようと思います。大きく分けて3点。

① そもそもTLSはOSIモデルではトランスポート層に位置するプロトコルで、WEBでの利用であれば、HTTPの下位に入ります。
HTTP等のプレゼンテーション層・アプリケーション層の通信を下位レベルで暗号化することが目的なので当然ですね。

② TLSのセッション確立は、
1. サーバ証明書送信 + 必要に応じてクライアント証明書を要求
2. 要求があればクライアント証明書送信
3. ごにょごにょ(証明書検証、プリマスタシークレット送信・マスタシークレットの生成、MACの交換・検証…)
4. 暗号化鍵生成
5. アプリケーション層の通信を開始
という手順で行われます。

③ locationディレクティブは、HTTPヘッダのGETやPOST等メソッド名の後に続くパスをもとに振り分けます。すなわち、アプリケーション層の情報を元にしています。

②を見ると、「クライアント証明書の利用の有無」のあとに「アプリケーション層の通信」が行われるわけですから、③のlocationディレクティブ判定=アプリケーション層の通信が行われるころには、すでにTLSのセッションは確立(②は終わっている)してしまっています。「クライアント証明書の使用の有無」も含めて、すでに話がまとまってしまっているため、後から蒸し返すことはできないというわけです。

HTTPの通信はTLSのセッション確立を前提とするため、locationディレクティブ(HTTPヘッダの一部)はTLSのセッション確立後に処理される。クライアント証明書の使用の有無はTLSのセッション確立時にしか決定できず、後からlocationディレクティブの内容によって切り替えることはできない。ということですね。

結局この問題をどう解決したかというと、「サーバ証明書のみ利用する仮想サーバ」「サーバ証明書とクライアント証明書の両方を利用する仮想サーバ」の二つを起動して、ポート番号で振り分けるという形態にしました。
安全性の確保という点でも、管理者用のエリアをより確実に隔離することにつながるので、この方が良かったですね。

さて、見返してみると誰得にもほどがあるような記事になってしまいましたが、広告がうっとうしかったのでご容赦ください。(論理の飛躍?気にしない気にしない)
しばらく時間ができそうなので、技術系の記事・エッセイともに公開をしていこうと思います。

インフルエンザが流行ってきていますが、くれぐれも気を付けたいですね。ではでは。
 


 
   WEBサイト/ページ    TB(0)    CM(0)    EDIT    ページ↑

コメント投稿


 管理者だけに表示

コメント

トラックバック

この記事へのトラックバック:

プロフィール

JDB Luigi

Author:JDB Luigi
どこにでもいるようなありふれた人間・・・という訳でもなく、かと言って怪しい宗教を信仰する変人という訳でも無い。

基本的に掲載しているコード等は煮ていただいても焼いていただいても結構ですが、利用は自己責任にてお願いいします。
また、バグ・アドバイス等もしあればよろしくお願いします。

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。