LDAP認証の基礎
LDAPとは何か、ログイン認証との関係、そして社内システムでよく見るログインID存在チェック→権限チェック→LDAP認証の流れを理解する
TL;DR
- LDAP はユーザー情報(アカウント・所属・権限)を一元管理するためのプロトコル/ディレクトリサービス
- LDAP認証とは「LDAPサーバーに問い合わせてパスワードを検証する」行為であり、ログイン認証の1手段
- 社内システムでは「アプリDB側でID存在確認 → 権限チェック → LDAPでパスワード検証」の順で行うことが多い
LDAPとは何か
LDAP(Lightweight Directory Access Protocol)は、ユーザーアカウントや組織情報を木構造(ディレクトリ)で管理し、検索・認証するためのプロトコル。
代表的な実装:
| 製品 | 概要 |
|---|---|
| Active Directory(Microsoft) | 企業でもっとも普及しているLDAP互換のディレクトリサービス |
| OpenLDAP | オープンソースのLDAPサーバー |
| AWS Directory Service | AWSが提供するマネージド型のディレクトリサービス |
ディレクトリ構造
LDAPはデータを「エントリ」の木構造で管理する。ルートから部門・グループ・ユーザーという階層で整理される。
dc=example,dc=com ← ドメイン(ルート)
└── ou=People ← 組織ユニット(部門)
└── uid=yamada ← ユーザーエントリ
├── cn: 山田 太郎
├── mail: yamada@example.com
├── memberOf: ou=dev-team
└── userPassword: (ハッシュ)各エントリは DN(Distinguished Name) という一意のパスで識別される。
上記の uid=yamada の DN は uid=yamada,ou=People,dc=example,dc=com となる。
LDAP認証とは何か
「LDAP認証」とは、パスワードの検証を自前のDBではなくLDAPサーバーに委ねること。
通常のDB認証との比較:
| 比較項目 | DB認証(自前) | LDAP認証 |
|---|---|---|
| パスワードの保管場所 | アプリのDB | LDAPサーバー(AD等) |
| アカウント管理 | アプリごとに独立 | 社内で一元管理 |
| 退職時の対応 | 各アプリで無効化が必要 | LDAPを無効にするだけで全システムに反映 |
| 向いているシステム | 一般公開のWebサービス | 社内システム・イントラ |
LDAP認証の流れ(技術的な詳細)
アプリがLDAPサーバーに問い合わせる際の手順:
1. アプリ → LDAPサーバーへ管理用アカウント(サービスアカウント)でバインド(接続)
2. アプリ → ユーザーの DN を検索(uid=yamada を探す)
3. ユーザーの DN が見つかったら、その DN + 入力パスワードで再バインドを試みる
4. 再バインドが成功 → パスワードが正しい(認証成功)
5. 再バインドが失敗 → 認証失敗(パスワード不一致)パスワード自体はアプリに届かず、LDAPサーバーが照合した結果だけが返ってくる。
社内システムでよくある認証フロー
社内業務システムでは、以下の3段階で認証・認可を行うことが多い。
ログイン画面
│
▼
① ログインID存在チェック(アプリDB)
│
▼
② ログインIDの権限チェック(アプリDB)
│
▼
③ 社内LDAP認証(LDAPサーバー)
│
▼
ログイン成功① ログインID存在チェック(アプリDB)
アプリ独自のDBを参照し、入力されたログインIDがこのシステムに登録されているかを確認する。
SELECT * FROM users WHERE login_id = :loginId AND deleted_at IS NULLなぜこのチェックが必要か?
LDAPは全社員のアカウントを管理しているが、このシステムを使える人は限られる場合がある(部署限定・契約ユーザーのみ等)。LDAPに問い合わせる前にシステム固有の登録チェックを挟む。
② ログインIDの権限チェック(アプリDB)
登録済みであることを確認した上で、そのユーザーがこのシステムにアクセスできる状態かを確認する。
確認すべき内容の例:
- アカウントが有効か(ロックされていないか)
- アクセス可能な期間内か(有効期限)
- 必要なロール・権限を持っているか
SELECT role, is_active, expires_at FROM users WHERE login_id = :loginIdなぜLDAP認証の前に行うか?
LDAPへの問い合わせはネットワーク越しの処理になるため、アプリDB側で弾けるものは先に弾くことで不要な外部通信を減らせる。また、エラーメッセージの粒度を細かくしやすい(「このシステムに権限がありません」などのメッセージを返せる)。
③ 社内LDAP認証(LDAPサーバー)
①②を通過したユーザーに対して、入力されたパスワードをLDAPサーバーで検証する。
アプリ → LDAPサーバーへ接続
→ uid=yamada,ou=People,dc=example,dc=com で検索
→ 見つかったDNと入力パスワードでバインド試行
→ 成功 → ログイン完了
→ 失敗 → 認証エラー(パスワードが違う or アカウントがLDAPでロックされている)パスワードの管理責任がLDAP側にあるため、アプリはパスワードを保存せず、変更・ロック管理もLDAP(Active Directory等)の管理者に委ねられる。
各ステップのエラーハンドリング
| ステップ | 失敗の意味 | 返すべきレスポンス |
|---|---|---|
| ①ID存在チェック | このシステムに未登録 | 「IDまたはパスワードが違います」(情報を明かさない) |
| ②権限チェック | 有効期限切れ・ロック等 | 「このアカウントは使用できません」など状況に応じて |
| ③LDAP認証 | パスワード不一致 or LDAPロック | 「IDまたはパスワードが違います」 |
①と③でメッセージを分けると「このIDが登録されているか」が攻撃者に分かってしまうため、通常は①③は同じメッセージにまとめる。
よくある落とし穴
LDAPサーバーがダウンしたときの設計を忘れる
LDAP認証は外部サービスへの依存になる。LDAPが落ちると全員ログイン不能になる。タイムアウト設定・フォールバック・障害時の通知を考慮する。
LDAPへの接続をサービスアカウントなしでやろうとする
匿名バインドを許可していないLDAPサーバーは多い。DN検索のためのサービスアカウント(bind dn / bind password)が必要になるため、認証情報の安全な管理(環境変数・Secrets Manager等)が必要。
ユーザーの入力をそのままLDAPクエリに使う(LDAPインジェクション)
uid=* や )(uid=* のような文字列を入力されると、意図しない検索結果が返ることがある。ユーザー入力の特殊文字をエスケープしてからLDAPクエリに組み込む。
LDAPとアプリDBのアカウント状態が乖離する
LDAPで無効化されたのにアプリDB側のユーザーが有効のまま(またはその逆)になりうる。権限チェックをどちら優先にするか・同期の仕組みをどうするかを設計段階で決めておく。
関連
- HTTPステータスコードの使い分け(401・403の使い分けはLDAP認証の文脈でも重要)
- RFC 4511 - LDAP Protocol
- RFC 4513 - LDAP Authentication Methods