LDAPインジェクション:認証の「裏口」を塞ぐための最前線知識
現場でインシデント対応をしていると、SQLインジェクションには敏感でも、ディレクトリサービス(LDAP)の脆弱性を過小評価しているエンジニアにしばしば出会う。だが、LDAPは組織の認証基盤そのものだ。ここを突破されるということは、鍵を盗まれるどころか、鍵穴そのものを改造されるに等しい。
今日は、LDAPインジェクションの泥臭い現実と、それを技術で封じ込めるための「現場の作法」を共有しよう。
—
1. なぜLDAPは狙われるのか?(攻撃のメカニズム)
LDAPインジェクションの根本的な原因は、ユーザー入力を「そのまま」LDAPフィルタの一部として結合してしまうことにある。
例えば、ユーザーのIDとパスワードで検索をかける場合、以下のようなクエリが生成されるとしよう。
(&(uid=USER_INPUT)(userPassword=PASS_INPUT))
ここで攻撃者が USER_INPUT に admin)(|(uid= を入力したらどうなるか? クエリはこう変貌する。
(&(uid=admin)(|(uid=)(userPassword=PASS_INPUT))
結果として、userPassword のチェックが事実上無効化され、あるいは最初のユーザーが強制的に選択されるなど、認証が容易にバイパスされる。さらに “(ワイルドカード)を悪用すれば、組織内の全ユーザーの属性情報を総当たりで抜き取ることも可能だ。これは「教科書」の問題ではなく、明日の深夜に君が対応することになるかもしれないインシデントのシナリオだ。
—
2. 現場で使えるセキュアな実装コード
「ブラックリスト形式でメタ文字を置換する」という古いやり方は捨ててほしい。あれはイタチごっこに過ぎない。正解は、ライブラリによる適切なエスケープ処理と、バリデーションの二段構えだ。
PHPでの実装例(Laminas/Ldapの使用を推奨)
生の文字列連結は絶対にNG。ライブラリが提供するエスケープ関数を必ず通すこと。
search($filter, …);
?>
Pythonでの実装例(ldap3ライブラリ)
Pythonであれば ldap3 ライブラリの escape_filter_chars を使うのが定石だ。
from ldap3.utils.conv import escape_filter_chars
def get_user_dn(user_input):
# ユーザー入力をLDAPフィルタ用にエスケープ
safe_input = escape_filter_chars(user_input)
# テンプレートに安全に埋め込む
ldap_filter = f”(&(uid={safe_input})(objectClass=inetOrgPerson))”
return ldap_filter
これにより、ユーザーが ‘)(uid=’ と入力しても
‘)\28uid=\2a’ のように安全に変換され、ロジック破壊を防げる
—
3. 防御の「最後の砦」:WAFとアーキテクチャの考え方
コードでの対策が基本だが、防御は多層であるべきだ。
WAF(ModSecurity等)でのシグネチャ対策
アプリケーション側で漏れがあった場合に備え、WAFでLDAP特有のメタ文字を含むリクエストを検査する。
ModSecurityのルール例(簡易版)
LDAPのメタ文字を含むリクエストを検知・ブロック
SecRule ARGS “[\\(\)\&\|\=]” \
“id:10001,phase:2,deny,status:403,msg:’LDAP Injection Attempt Detected'”
運用の心得:最小権限の原則
LDAPサーバーに接続するアプリケーションの「サービスアカウント」の権限を見直してほしい。WebアプリがLDAPの全ディレクトリを読み取る権限を持っている必要はないはずだ。
- 読み取り範囲の制限:特定のOU(Organizational Unit)のみにアクセスを限定する。
- 書き込み権限の剥奪:認証用途であれば、バインド(認証)のみを許可し、属性検索権限を極限まで絞る。
—
セキュリティチーフからの最後のアドバイス
LDAPインジェクションを撲滅する鍵は、「ユーザー入力を一切信用しない」という強迫観念を持つことだ。
コードを書くとき、「この変数は本当にLDAPのフィルタとして使われるのか?」「もし攻撃者がここを操作したらどうなるか?」と自分に問いかけてほしい。セキュリティは、ツールを導入して終わりではない。個々のエンジニアがデータの「流出先」と「文脈」を理解したときに初めて、強固なシステムが出来上がる。
さあ、今すぐリポジトリの検索機能や認証モジュールを grep して、文字列連結でクエリを構築している場所がないか確認しよう。君のシステムを守れるのは、君自身の指先だけだ。
コメント