LDAP 삽입
정의
입력값을 적절한 처리 없이 LDAP 쿼리문이나 결과의 일부로 사용하는 경우, LDAP 쿼리문이 실행될 때 공격자는 LDAP 쿼리문의 내용을 마음대로 변경할 수 있으며, 이로 인해 프로세스가 명령을 실행한 컴포넌트와 동일한 권한을 가지고 동작하게 된다.
안전한 코딩기법
기본적인 방어법은 유효성 검사이다.
- 올바른 인코딩 함수를 사용해 모든 변수 이스케이프 처리
- 화이트리스트 방식의 입력값 유효성 검사
- 민감한 정보(사용자 패스워드 등)가 포함된 필드 인덱싱
- LDAP 바인딩 계정에 할당된 권한 최소화
코드예제
안전하지 않은 코드예제로, 사용자 입력을 그대로 LDAP 질의문에 사용하고 있으며 이 경우 권한 상승 등 공격에 노출될 수 있습니다.
#LDAP 삽입(안전X)
config = {
"bind_dn": "cn=read-only-admin,dc=example,dc=com",
"password": "password",
}
def ldap_query_bad(request):
search_keyword = request.POST.get('search_keyword', '')
dn = config['bind_dn']
password = config['password']
address = 'ldap.badSource.com'
server = Server(address, get_info=ALL)
conn = Connection(server, user=dn, password, auto_bind=True)
search_str = '(&(objectclass=%s))' % search_keyword
conn.search('dc=company,dc=com', search_str, attributes=['sn', 'cn', 'address', 'mail', 'mobile', 'uid'])
return render(request, 'success.html', {'data': conn.entries})
다음은 안전한 코드 예제로, 사용자 입력 중 LDAP 질의문에 사용될 변수를 이스케이프하여 질의문 실행 시 공격에 노출되는 것을 예방할 수 있습니다.
#LDAP 삽입(안전O)
def ldap_query_good(request):
search_keyword = request.POST.get('search_keyword', '')
dn = config['bind_dn']
password = config['password']
address = 'ldap.goodSource.com'
server = Server(address, get_info=ALL)
conn = Connection(server, user=dn, password, auto_bind=True)
escape_keyword = escape_filter_chars(search_keyword)
search_str = '(&(objectclass=%s))' % escape_keyword
conn.search('dc=company,dc=com', search_str, attributes=['sn', 'cn', 'address', 'mail', 'mobile', 'uid'])
return render(request, 'success.html', {'data': conn.entries})
입력데이터 검증 및 표현/LDAP 삽입
[참고문헌] Python 시큐어코딩 가이드(2022) / KISA(한국인터넷진흥원)