설명
LDAP 서버에 익명으로 바인딩하면 서버는 클라이언트의 신원을 확인하지 않습니다. 실제로 읽거나 수정할 수 있는 데이터는 서버의 익명 접근 권한에 따라 달라집니다. 민감한 디렉터리 정보나 변경 작업을 익명 사용자에게 허용하면 정보 유출이나 무단 변경으로 이어질 수 있습니다.
잠재적 영향
- 민감한 데이터 노출: 익명 사용자가 LDAP 서버에 접근하여 조직의 사용자 정보, 그룹 목록 등을 조회할 수 있습니다.
- 권한 없는 데이터 조작: 인증 없이 데이터를 수정할 수 있는 경우, 공격자가 권한을 상승시킬 수 있습니다.
- 서비스 악용: 익명 사용자가 대량의 LDAP 요청을 보내 서비스 거부(DoS) 공격을 수행할 수 있습니다.
해결 방법
- 보호가 필요한 연결에는 서버가 지원하는 인증 방식을 명시적으로 설정하세요.
"simple"인증에는 검증된 TLS를 사용하고,"strong"문자열만으로 안전한 SASL이 구성된다고 가정하지 마세요. - 최소 권한 계정을 사용하고 비밀번호는 비밀정보 저장소나 접근이 제한된 실행 환경에서 주입하세요. 비밀번호가 없거나 비어 있으면 연결을 거부하세요.
- 서버에서 익명 사용자의 민감한 데이터 조회·수정 권한을 차단하세요. 클라이언트의 인증 설정만 바꾸어도 서버의 익명 권한이 변경되는 것은 아닙니다.
예시
변경 전
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 연결에서 인증합니다. 환경 변수 자체가 비밀정보 저장소는 아니므로 실행 환경의 접근 권한과 로그도 보호해야 합니다.