발생원인


LDAP 명령어에 대한 검증 처리가 없는 경우 발생

 

영향


 정보 유출/ 조작



<참고> LDAP(Lightweight Directiry Access Protocol)은 조직이나 개체, 그리고 인터넷 이나 기업내의 인프라넷등 네트워크 상에 있는 파일이나 장치들과 같은 자원등의 위치를 찾을 수 있게 해주는 소프트웨어 프로토콜이다.  

LDAP은 네트웍 내의 디렉토리 서비스 표준인 X.500의 일부이다. 


Netscape는 자신들의 커뮤니케이터 최신판에 LDAP을 표함하고 있다. 마이크로소프트는 액티브 디렉토리라고 부르는 제품의 일부로서 LDAP을 포함하였다. 노벨 네트워크 디렉토리 서비스는 LDAP와 상호운영된다.



<참고2> LDAP은 어떻게 작동하는가?

LDAP디렉토리 서비스는 클라이언트-서버 모델에서 기초하는데 하나 또는 그 이상의 LDAP서버들이 LDAP 디렉토리 트리 또는 백엔드 데이터베이스를 구성하는 자료를 가지고 있다. LDAP 클라이언트는 LDAP서버에 연결해 질의하며 서버는 답 또는 클라이언트가 더 많은 정보를 얻을 수 있는 포인터를 가지고 응다한다.


클라이언트는 어떤 LDAP서버에 연결하던간에 동일한 디렉토리 구조를 본다. 


LDAP문서 참조: http://jabcholove.tistory.com/89

 

 

LDAP 자바에서 사용하기

 

출처: http://mrtint.tistory.com/708

 

현재의 개발 환경에서는 LDAP 를 통한 Directory 정보들을 수집해야할 일이 상당히 많다.

여지껏 .NET 으로의 개발은 여러번 있어서 어렵지 않게 했지만.. Java 로 해야할 일이 생겨서 이리저리 API들을 확인하면서 작업해 보았다.


일단 핵심이 되는 API는 javax.naming 이라는 패키지, 이부분이 모든 LDAP 통신을 위한 API들이 있는 패키지 이므로 기억해 두는 것이 좋다.


핵심이 되는 몇몇 Class 들이 있는데, 그 중 4개 정도가 주된 것이니 이 또한 기억해두도록 하자.

 


 

javax.naming.directory.InitialDirContext

javax.naming.directory.SearchControls

javax.naming.directory.SearchResult

javax.naming.directory.Attribute

 



  1. javax.naming.directory.InitialDirContext
    • 디렉토리 서비스의 Base 가 되는 클래스 이다. 좀 더 이해하기 쉽게 말하면, JDBC의 Connection 인터페이스와 같은 역할을 한다. LDAP 통신을 하기위한 Host 정보나 인증 절차를 위한 계정, 비밀번호와 같은 것들을 설정하여 해당 디렉토리 서버와의 연결을 만들어내는 역할을 한다.
  2. javax.naming.directory.SearchControls
    • 생성된 Context 를 통해서 LDAP 경로 및 필터 문자열을 통해 개체 정보를 검색하는 역할을 한다.
  3. javax.naming.directory.SearchResult
    • 검색된 결과 개체의 데이터 유형이다. 해당 클래스의 getAttributes() 메소드를 이용하여 해당 개체의 정보들을 추출해 낼 수 있다.
  4. javax.naming.directory.Attribute
    • 이는 AD의 개체의 특정 항목 정보를 담고 있다. 

 


구글링을 통해서 검색해 보면 얼마든지 Java 라는 언어로 LDAP 프로그래밍 하는 방법은 나와있지만 대부분이 샘플 예제를 덩그러니 가져다 놓은 케이스들이 많아서 실제 구현에는 그닥 도움이 안되는 부분이 있다. 그래서 개발 도중에 삽질을 했던 부분이 다소 있다. 이런 부분을 속 시원하게 긁어주는 편이 글을 보는 이로 하여금 더 도움이 되지 않을까 한다.


<LDAP 접속 정보 설정은 어떻게 하는가>


 

Hashtable<String, String> properties = new Hashtable<String, String>();

properties.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");

properties.put(Context.PROVIDER_URL, path);

properties.put(Context.SECURITY_AUTHENTICATION, "simple");

properties.put(Context.SECURITY_PRINCIPAL, userId);

properties.put(Context.SECURITY_CREDENTIALS, passwd);


거의 구글링을 해보면 뒤의 설정 정보가 거의 대부분이다. 그 이상은 더 뭘 해줄 필요가 없다.
properties.put(Context.SECURITY_AUTHENTICATION, "simple"); 
-> 여기는 simple 대신에 none 을 써주면 아래 userId 나 passwd 를 설정해주지 않아도 된다. 단 해당 LDAP 호스트에서 익명 조회가 가능하도록 설정 해 두었을때 이야기다.

properties.put(Context.SECURITY_PRINCIPAL, userId); 
-> 예를 들어 계정이 foo 라는 계정으로 인증하길 원할 경우에는 단순하게 foo 를 입력하면 인증이 안되는 경우가 발생 된다. 왜 안되지 하고 있지말고 다음과 같이 해보자. 그러면 인증이 제대로 될거다. 도메인 컨트롤러 호스트명이 ds.mycompany.com 이고 도메인 컨트롤러 이름이 mycompany 라고 치자. 이럴 경우 foo 라고 해봐야 계속 인증에 실패만 할 것이다.
foo@mycompany 혹은 foo@ds.mycompany.com 으로 시도 해보면 인증이 이루어지는 것을 확인할 수 있다.

또한 패스워드 부분이 null 이거나 공백없는 문자열 ("") 일 경우에는 인증 과정이 이루어지지 않는다는 것을 기억하자.

<javax.naming.directory.DirContext.search(String name, String filter, SearchControls) 메소드의 name 이라는 인수는 뭐하는 놈인가?>

NamingEnumeration<SearchResult> results = context.search("OU=Employees,DC=ds,DC=mycompany,DC=com", filterString, searcher);

Copy & Paste 해온 소스를 돌렸을때 제일 짜증나는 부분이 여기였다. 첫번째 인수인 name 이라는 녀석이 너무 불분명해서 찾기가 조금 힘든 편이였는데, 쟤는 DC 이름 OU, CN 과 같은 디렉토리 폴더 정보들을 명시해주는 부분이었다. 트리 구조 형태로 되어있는 자료형의 디렉토리 서비스에는 베이스가 되는 디렉토리 정보가 필요한데, 그 부분을 명시해 주는 것이다. 공란으로 해놓은 곳도 많은데 이는 보안 상 공란 처리 했지 싶다.

소스는 첨부파일로 확인하면서 내용을 보면 더 쉽게 이해 갈 수 있다.


블로그 이미지

오픈이지 제로킴

시큐어코딩 교육/컨설팅 전문가 그룹

티스토리 툴바