JNDI 주입 (JNDI Injection)
JNDI Injection
설명
JNDI(Java Naming and Directory Interface)는 이름으로 객체를 조회하는 API입니다. 문제는 조회에 쓰이는 이름이 사용자 입력으로 제어될 때 발생합니다. 공격자는 입력값에 ldap://, rmi://, iiop:// 같은 절대 URL을 넣어 공격자가 운영하는 원격 디렉터리/레지스트리로 유도하고, 악의적인 객체나 참조를 반환시켜 애플리케이션에서 로드·실행되게 만들 수 있습니다. 이로 인해 원격 코드 실행(RCE), 내부 네트워크 스캔/접근, 민감정보 유출 등이 발생할 수 있습니다. 흔한 공격 시나리오는 InitialContext.lookup 또는 DirContext.lookup/search에 사용자 입력이 그대로 전달되고, 그 값이 원격 LDAP/RMI 서버를 가리키도록 조작되는 경우입니다.
잠재적 영향
Remote Code Execution (원격 코드 실행): 악성 Reference/오브젝트를 로드하게 만들어 애플리케이션 권한으로 임의 코드를 실행할 수 있습니다.
Sensitive Data Exposure (민감정보 유출): JNDI를 통해 불필요한 객체/리소스에 접근하여 자격증명, 설정 값, 시스템 정보가 노출될 수 있습니다.
SSRF/Internal Access (서버사이드 요청 위조/내부망 접근): 외부로 보이는 입력을 통해 애플리케이션이 내부 LDAP/RMI/IIOP 엔드포인트로 요청을 보내도록 유도할 수 있습니다.
Service Disruption (서비스 장애): 악의적인 조회로 자원 고갈 또는 예외 연쇄를 유발해 서비스 중단을 일으킬 수 있습니다.
해결 방법
사용자 입력 직접 사용 금지: InitialContext.lookup/Context.lookup/DirContext.search 등에 신뢰되지 않은 값을 그대로 전달하지 않습니다.
고정 JNDI 이름 사용: 가능한 한 java:comp/env/... 등 애플리케이션 내부 고정 이름만 사용합니다.
강력한 화이트리스트: 불가피하게 사용자 선택이 필요하면 사전에 정의된 키→JNDI 이름 매핑(화이트리스트)만 허용하고, 임의 문자열이나 절대 URL(ldap://, rmi://, iiop:// 등)은 거부합니다.
엄격한 검증: 허용된 prefix(java:comp/env/)만 통과시키는 정규식/검사를 적용하고, 스킴이 포함된 절대 URL은 모두 차단합니다.
원격 코드베이스 비활성화 및 최신 JDK: JVM 보안 속성에서 trustURLCodebase=false를 설정하고, JDK 최신 보안 업데이트를 적용해 원격 코드 로딩을 차단합니다.
최소 권한 및 네트워크 세분화: 애플리케이션 런타임 계정 권한을 최소화하고, 서버가 임의의 LDAP/RMI로 나가지 못하도록 egress 방화벽/ACL을 적용합니다.
취약한 코드 및 안전한 코드 예시
취약한 코드
안전한 코드
설명:
취약한 코드: 사용자 입력이 그대로 ctx.lookup에 전달됩니다. 공격자는 입력값을 ldap://attacker.example/..., rmi://... 등으로 지정하여 원격 서버의 악성 참조/객체를 반환시키고, 애플리케이션이 이를 로드하도록 유도해 RCE, 내부망 접근, 정보 유출을 유발할 수 있습니다.
안전한 코드: 사용 가능한 리소스를 사전 정의된 화이트리스트(Map)로 제한하여 임의 문자열이나 절대 URL을 사용할 수 없게 했습니다. 또한 java:comp/env/ 같은 내부 네임스페이스만 허용함으로써 외부 LDAP/RMI로의 조회를 원천 차단합니다. 이로써 사용자 입력이 JNDI 조회에 직접 반영되지 않으며, 원격 코드 로딩과 SSRF 위험이 제거됩니다.
참조
Last updated