Basic認証の危険性とLDAP化の概要
多くの読者の皆さんがご存じのように、パスワード認証を要求するWebページをApache上で作成するためには、通常は.htaccessと.htpasswdなどを用いたBasic認証を使用します。
たとえば、http://www.example.com/secret/以下にてパスワード認証を実現するには次のような設定を行うのが一般的でしょう。
この方式ではhtpasswdコマンドなどを用いて暗号化されたパスワードを作成し、ファイルシステム上のどこかで管理しておく必要があります。数年前、.htpasswdファイルをDocumentRoot内に保存しているサイトが多数存在していたため、検索エンジン経由で容易にパスワードファイルを取得できる状態となっていました。
それから数年を経て、「DocumentRoot以下に.htpasswdファイルを保存するのは危険」という認識は広まってきましたが、共有サーバの場合、攻撃者が自らのCGIを悪用することで、共有サーバ上に存在する.htpasswdファイルを検索、内容を解析するという攻撃も現れ始めました。環境次第では、どこに.htpasswdファイルを保存しても危険な状態になっていたのです。
近年では管理者のセキュリティ意識も高まってきたため、このように危険な状態のサーバはほとんど無いでしょうが(思い当たる方はすぐに対処してくださいね!)、パスワード情報がLDAP上に保存されているとすればどうでしょうか?
もうパスワードの置き場所について悩むことはありません。当然検索エンジンでパスワードファイルを拾われることはありませんし、悪意のあるCGI経由でパスワードが奪われることもありません。なぜなら攻撃者はLDAPバインド用のDNやパスワードを知らないためです。当然WebサーバやLDAPサーバの設定が適切でなかったり、サーバ自体がクラックされてしまえばその限りではありませんので100%安全と言えるわけではありませんが、設定次第では非常にセキュアで便利な環境を提供することができます。
Apacheのインストール
ApacheでLDAPに対応したBasic認証を実現するためには、LDAP関連のApacheモジュールをインストールしておく必要があります。今回検証に用いたApacheは執筆時の最新バージョンである2.2.6です。本連載で毎回使用しているCentOS-4.xにおけるApacheのバージョンは2.0.52であり、LDAP認証モジュールの設定方法なども最新版と異なるため、今回はApacheバージョン2.2.6を/usr/local以下にインストールしてみました。もちろんOS標準の2.0.52でもLDAP認証を実現することはできますので、詳細は2.0.52用のドキュメントを参照してみてください。
Apache-2.2系でLDAP認証を実現するためのモジュールは、mod_authnz_ldapです。同じようにLDAPを参照するためのmod_ldapというモジュールも存在するため注意してください。こちらは認証ではなくLDAPサーバとの接続プールやキャッシュ用に使用されるモジュールです。mod_authnz_ldapはmod_ldapを利用することで、効率的にLDAPサーバの資源を使用することができます。
なお、mod_authnz_ldapを使用するためにはmod_ldapが必要ですし、mod_ldapはLDAPに対応したapr-utilに依存します。すでにLDAPに対応したapr-utilが導入されている場合はそれほど気にしなくて良いのですが、Apache付属のapr-utilを導入する場合には図1のように--with-ldapオプションを忘れないでください。
混乱しがちなのでまとめておきますと、それぞれのオプションの意味は次表の通りです。
--with-ldap | LDAP対応apr-util作成のため |
--enable-authnz-ldap=shared | mod_authnz_ldap.soを作成 |
--enable-ldap=shared | mod_ldap.soを作成 |
設定
今回は、レンタルサーバのような環境で、それぞれのユーザにアクセス解析サービスを提供させてみたい状況を想定します。アクセス解析画面ではパスワード認証を要求し、それ以外のユーザはページにアクセスすることができません。また、ユーザは普段FTP経由でコンテンツをアップロードするため、ユーザ名、パスワードはLDAPサーバに存在するものとします。FTPとLDAPの連携については過去の記事を参考にしてみてください。まずは簡単な仕様を確認しておきましょう。
アクセスログ解析データは
/home/support/ユーザ名/analog
以下に存在するとして、
http://www.example.com/logs/ユーザ名/
にて認証を要求した上で参照できるものとします。suzukiというユーザはhttp://www.example.com/logs/suzuki/にアクセスし、ユーザ名、パスワード、ともに正しい情報を入力すればページが表示されるという仕組みです。今回の方式では、suzukiという認証済みのユーザがhttp://www.example.com/logs/tanaka/にアクセスしてしまうと、別ユーザの画面が見えてしまいますが、これについては手抜きで気にしないものとします。
LDAP URL
今回の設定ではLDAP URLというLDAP特有のURLが登場します。たとえば本稿も掲載されている技術評論社のポータルサイトのアドレスは次のように表すことができます。
http://gihyo.jp:80/admin/serial/01/ldap
つまり、gihyo.jpの80番ポートの中で、コンテンツは/admin/serial/01/ldapにある、という意味です。LDAPの場合、次のようなLDAP URLを使って検索条件などを表すことができます。
例を挙げた方がわかりやすいですね。
というURLであれば、次のコマンドと等価です。条件などを?の後につづっていく形となります。
LDAPに対応したソフトウェアの設定では、このようなLDAP URLを用いるものと検索ベースや検索条件などを別々に定義するものがあります。両方の形式に対応できるよう表示に慣れておきましょう。
LDAPデータ登録
今回Basic認証に必要なユーザ名やパスワードはFTPログインに使用するものをそのまま流用するものとします。検証に際してリスト4のようなエントリを使用しました。特殊な設定はなく、/etc/passwdや/etc/shadowと同等の意味を持ちます。
このような環境下で、たとえば認証画面でUser: tanaka、パスワード: tanakaと入力すれば認証済みになるとします。Apache側の設定としてはリスト5のようになります。いつもと違うオプションはAuthBasicProvider、AuthzLDAPAuthoritative、AuthLDAPURLです。
ここでmod_authnz_ldapの各オプションについて解説しておきます。それ以外のオプションに関しては、Apacheのドキュメントで確認してください。ちなみに筆者が普段使用するオプションはAuthLDAPBindDN、AuthLDAPBindPassword、AuthLDAPUrl、AuthzLDAPAuthoritativeくらいです。Require valid-userを使用しているため、それに伴いAuthzLDAPAuthoritative offを定義しています。
そのほか、認証時に入力させるユーザ名ではない値を環境変数REMOTE_USERに保存するためのAuthLDAPRemoteUserAttributeというオプションなどもありますが、使用する機会は少ないように思います。
AuthLDAPBindDN | LDAPサーバへバインドするためのバインドDN |
AuthLDAPBindPassword | 上記パスワード |
AuthLDAPUrl | LDAP URLの指定 |
AuthzLDAPAuthoritative | 認証が失敗したときに他の認証モジュールが認証を行うのを防ぐ |
認証と課金
場合によっては、今回のようなアクセスログ解析サービスを有料オプションとして提供したい場合もあるでしょう。その場合、FTP用にIDやパスワードを参照させますが、WebのBasic認証をパスさせない、という対策が必要になります。今までの連載でも触れてきましたように、LDAPでは検索フィルタを用いることでこのような機能を簡単に実装することができます。
たとえば検索フィルタが(&(objectClass=account)(servicetype=1))となっていれば、利用者の中でもservicetypeという属性が1であるユーザのみが検索対象となります。言い換えれば、有料オプション利用者のエントリではserviceType=1と定義しておき、それ以外のユーザではserviceType=0と定義しておけば良いのです。
もちろんserviceTypeという属性は筆者が勝手に決めたものであり、標準スキーマに含まれているわけではありませんので、次のようにして組み込んでおく必要があります。
これに合わせたユーザ用のLDIFはリスト8のようになります。
あとは検索フィルタを有効にしたhttpd.confを準備するだけです(リスト9)。AuthLDAPURLオプションをうまく設定します。
まとめ
今回はBasic認証用にLDAPを活用することで、冒頭に述べたとおり
- パスワードファイルの置き場所に悩まない
- パスワードを一元管理
- 検索フィルタを活用してサービス制限
といったことを実現することができました。また、LDAP URLを用いて検索フィルタや条件などを追加することができることもわかりました。2007年最後の記事となりましたが、来年も少しずつLDAPの使い道を紹介していく予定です。それではまた。