匿名LDAPバインド

匿名LDAPバインド

説明

匿名LDAPバインドでは、サーバーはクライアントの身元を確認しません。実際に読み書きできるディレクトリデータは、サーバーの匿名アクセス権限によって決まります。機密データや変更操作を匿名ユーザーに許可すると、情報漏えいや不正な変更につながるおそれがあります。

想定される影響

  • 機密データの公開: サーバーが許可している場合、匿名クライアントがユーザー情報やグループ一覧を取得できます。
  • 権限のない変更: 匿名の書き込み権限によりデータが改ざんされ、対象データによっては権限昇格につながる可能性があります。
  • サービスの悪用: 大量の匿名リクエストがサービス拒否につながるおそれがあります。

対処方法

  1. 保護が必要な接続には、サーバーが対応する認証方式を明示してください。"simple"認証には検証済みのTLSを使い、"strong"という文字列だけで安全なSASLが構成されると考えないでください。
  2. 最小権限のアカウントを使い、パスワードはシークレット保管先やアクセスを制限した実行環境から渡してください。パスワードが未指定または空なら接続を拒否してください。
  3. サーバー側で、匿名ユーザーによる機密データの読み書きを禁止してください。クライアントの認証設定を変えても、サーバーの匿名権限は変わりません。

例

変更前

java
import javax.naming.Context;
import javax.naming.directory.InitialDirContext;
import java.util.Hashtable;

public class UnsafeLDAP {
    public static void main(String[] args) throws Exception {
        Hashtable<String, String> env = new Hashtable<>();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        env.put(Context.PROVIDER_URL, "ldap://ldap.example.org:389");
        env.put(Context.SECURITY_AUTHENTICATION, "none"); // 匿名バインドを要求

        InitialDirContext ldapContext = new InitialDirContext(env);
    }
}

変更後

証明書とホスト名を検証できるLDAPSサーバーおよび信頼ストアが必要です。app-readerは必要な読み取り権限だけを与えた例のアカウントです。実際のアカウントDNへ置き換えてください。

java
import javax.naming.Context;
import javax.naming.directory.InitialDirContext;
import java.util.Hashtable;

public class SecureLDAP {
    public static void main(String[] args) throws Exception {
        Hashtable<String, String> env = new Hashtable<>();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        env.put(Context.PROVIDER_URL, "ldaps://ldap.example.org:636");
        env.put(Context.SECURITY_AUTHENTICATION, "simple"); // TLS接続でパスワード認証
        env.put(Context.SECURITY_PRINCIPAL, "cn=app-reader,dc=example,dc=org");
        env.put(Context.SECURITY_CREDENTIALS, getLdapPassword()); // 実行環境からパスワードを取得

        InitialDirContext ldapContext = new InitialDirContext(env);
        ldapContext.close();
    }

    private static String getLdapPassword() {
        // アクセスを制限した実行環境から渡されたパスワードを確認
        String password = System.getenv("LDAP_PASSWORD");
        if (password == null || password.isEmpty()) {
            throw new IllegalStateException("LDAP password is not set");
        }
        return password;
    }
}

説明:

  • 変更前: "none"で匿名バインドを要求します。アクセス範囲は、サーバーが匿名クライアントに許可する権限に従います。
  • 変更後: 外部から渡した空でないパスワードを使い、TLS接続で認証します。環境変数自体はシークレット保管先ではないため、実行環境とログへのアクセスも保護してください。

参考資料