仙石浩明の日記

2006年4月4日

DB サーバのセキュリティ向上策 (2)

KLab で採用している DB サーバのセキュリティ向上策を説明する前に、 DB アクセスの際に SSL クライアント認証を行なう方法について説明します。

DB サーバへのアクセスにおいて SSL クライアント認証を必須とし、

(a) 開発者が (デバッグ目的等で) DB アクセスを行なう時は、 その開発者個人が管理する SSL 秘密鍵を用いてアクセスするようにし、

(b) プログラムが DB アクセスを行なう時は、 そのプログラムの実行権限でのみアクセスできる SSL 秘密鍵を 用いるようにすれば、

普通のパスワード認証よりはセキュリティを向上させることができます。 SSL クライアント認証をサポートしている DB サーバであれば、 その機能を有効にするだけで良いので、とても手軽な方法です。

ここで注意したいのは、 普通に SSL を使う (つまり SSL による暗号化のみを行なう、 あるいは暗号化に加えて SSL サーバ認証のみ行なう) ことは、 あまり意味がない、ということです。

データセンタのラック内の通信の盗聴を心配しても仕方がないわけで、 通信路を暗号化すること自体には意味はないでしょう。 また、サーバ認証は接続先が意図したサーバか確認するための手段ですが、 これもラック内で、通信相手が意図通りのサーバでないか心配しても 仕方がないですね。

SSL クライアント認証をサポートしていない DB サーバでも、 拙作 stone を使えば、手軽に SSL クライアント認証を付け加えることができます。

例えば DB サーバへのアクセスを unix ドメインソケット /path/to/socket でのみ 受け付けている場合、このソケットへのアクセス権限を DB サーバの実行ユーザ (ここでは uid が 1001 番とします) 権限に限定して、 local ユーザがアクセスできないようにしておいて、 stone を次のように実行します。

stone -o 1001 -z verify \
      -z CApath=/usr/local/ssl/certs \
      -z key=/usr/local/ssl/private/db.pem \
      /path/to/socket 12345/ssl

「-z verify」が SSL クライアント認証を必須とするためのオプションです。 「-z CApath=/usr/local/ssl/certs」オプションで、 CA の証明書を置いてあるパスを指定します。

すると、その CA が署名した SSL 証明書に対応する秘密鍵を 持っているクライアントが、その SSL 証明書を提示して ポート 12345 番に SSL 接続してきた時のみ、 stone はそれを /path/to/socket へ中継します。

CA が署名した SSL 証明書ならなんでも OK とするのではなく、 特定の CA の特定の証明書のみを受け付ける場合は、

stone -o 1001 -z verify \
      -z CApath=/usr/local/ssl/certs \
      -z key=/usr/local/ssl/private/db.pem \
      -z depth=1 \
      -z re1='/CN=KLAB Root CA[/$]' \
      -z re0='/CN=dbuser[0-9]*[/$]' \
      /path/to/socket 12345/ssl

などのように、SSL証明書の発行対象の名称 (CN) を特定するための 正規表現 (この例では「/CN=dbuser[0-9]*[/$]」) を指定します。

なお、ここでいう証明書は、いわゆる「オレオレ証明書」で構いません。 つまり DB サーバの管理者が必要に応じて何枚でも独自に発行できます。

「オレオレ証明書」が問題となるのは、認証する側が認めていない CA が 証明書を発行する場合です。 例えばサーバ認証を行なう場合は、認証する側は WWW ブラウザなどになります。 WWW ブラウザのユーザが認めていない CA を勝手に立てて証明書を発行し、 ユーザにきちんと説明することなくその証明書を受け入れることを 強要すべきではありません。これがいわゆる「オレオレ証明書」です。

一方、クライアント認証の場合は、認証を行なうのはサーバ側であるので、 サーバの管理者が認める CA ならばなんでも構いません。 もちろんサーバの管理者が独自に立てた CA で OK です。

上記の例では、KLab で立てた「KLAB Root CA」が発行した証明書で、 かつその発行対象の名称 (CN) が「dbuser」+ 0桁以上の数字 の場合 のみ接続を受け付けます。

DB へアクセスする必要がある開発者と、DB へアクセスするプログラム それぞれに別々の証明書を発行すれば、DB 側で 誰からのアクセスか特定することが可能になります。

しかしながら、

(1) プログラム用の秘密鍵を誰が管理するのか?

(2) SSL クライアント認証にともなう負荷増大

という問題が残ります。(2) はコストを度外視すれば済むので、 高いパフォーマンスが要求されない場合は問題とならないかも知れません。 が、(1) はなかなかやっかいです。

プログラムの開発者は、プログラムの実行権限で読むことができるファイルは 何でも読めます。例えば、秘密鍵を読んで特定の場所へコピーするよう プログラムを改変することは至って簡単でしょう。 したがって、プログラム専用の秘密鍵というのは実は 開発者全員で共同管理している秘密鍵と大差ありません。

プログラムの開発者なら誰でも DB にアクセスできる、 という状況を許容するなら、わざわざクライアント認証のような 負荷の高い方法を選択しなくても、と思うのが人情です。

ではどういう方法がよいでしょうか?

(続きは次回に)

Filed under: stone 開発日記,システム構築・運用 — hiroaki_sengoku @ 08:03

No Comments »

No comments yet.

RSS feed for comments on this post.

Leave a comment