PHPのldap_bindとActiveDirectory

PHPldap_bindは全く関係ないんですけど、PHPとADを使ったお仕事で出てきたので、覚書程度に書かせてください。


注意:当方、LDAPの知識もADの知識も全くございません。認識を誤った記述をしている場合があります。

環境

PHP 5.4.11
OpenLDAP 2.4.33(ldapクライアントとして)

やりたいこと

  • ldap_bindを使ったLDAP認証を行いたい
    • 対向先がADとOpenLDAPでもOKな感じにしたい
    • 所属組織(OU)を意識した認証をしたい(重要)
    • あるユーザのDN表現は以下
      • cn=ryozi,ou=kaihatu,dc=hoge,dc=local
    • dcの値をみてわかるとおり、ドメインhoge.local

問題点

  • OpenLDAPサーバとPHPLDAP通信する場合に、bindで与える情報
    • uid=ryozi,ou=kaihatu,dc=hoge,dc=local (schemeにより、変化するはず)
    • パスワード
  • ADの場合とPHPLDAP通信する場合に、bindで与える情報
    • ryozi@hoge.local
    • パスワード
  • OpenLDAPの場合のフォーマットと違う。OUの情報が抜けている。
    • この場合、所属組織(OU)を意識せずにbind出来てしまう。
    • 所属(開発部、総務など)を選ばせて、認証したい場合に問題。
      • 総務の人のIDを入力して、所属を開発部で選んだのにbindできちゃった!みたいなことになる。
      • 別にsearchすれば正しいDNが得られるのでそれでチェックしてもいいし、これが問題にならないケースのほうが多いと思うけど。
  • 調べた使用例で最も多いもの。php.netでユーザが寄稿したサンプルもこれ。*1

せいかい

おとなしくユーザのDNを指定する。
このやり方で出来るのに、なんで"ryozi@hoge.localなフォーマットじゃないとダメ!!"という情報があるのかわからん。
当時はダメで、現在はサポートしてくれるようになったんだろうか?

$ok = @ldap_bind("cn=ryozi,ou=kaihatu,dc=hoge,dc=local", "パスワード");
if(!$ok){
    die("bind failed.");
}
echo("bind successed");


OpenLDAPのときと若干違うけど、それはまぁ何とかなる範囲でしょう。

追記

やっぱり嘘でした!変だと思ってたわ!知ってた!!

「ryozi@hoge.local」な認証は、
属性sAMAccountNameに"ryozi"とある場合に有効で、
属性CNに"ryozi"という値が入っている保障がないから。両方同じならどちらの形式でも当然通る。
なのでsAMAccountName(Windowsログオン時のアカウント)でやるなら、

  1. 管理者DNで認証→IDをsAMAccountNameで検索→得られたDNの値の検証→DNの値を使って認証(OpenLDAPでも通用)
  2. 「ID@ADのドメイン名」で認証→IDをsAMAccountNameで検索→得られたDNの値の検証(OpenLDAPでは使えない)

このどちらかかなー。
前者はOpenLDAP互換だが、信頼できるアカウントが必要。
後者は前者より手数が少なくて済むが、AD依存。

「"ryozi@hoge.local"な形式じゃないとダメ!!1」
みたいな記事ばかりで、ADも買えない貧乏な僕はがっかりです。

だいたいそういう記事に限って「LDAPでやり取りするとき、入力されたIDを使う際、こういうエスケープ処理が必要」ってのもないし。
bind時のDNを構成するときのエスケープと、フィルタのエスケープの2つについて言及してるところが余り見ないところをみると、
結構、LDAPインジェクションできちゃうんじゃね、とか思うわけです。はい。
(LDAPについて言えば、ちゃんとRFC2253,RFC2254にかかれてます。ADは知らない。)

*1:4年前だから事情が変わったのかもしれんが。