[시큐어코딩 가이드] LDAP 삽입

 

 

 

■ 입력데이터 검증 및 표현

 

프로그램 입력 값에 대한 검증 누락 또는 부적절한 검증, 데이터의 잘못된 형식지정, 일관되지 않은 언어셋 사용 등으로 인해 발생되는 보안약점으로 SQL 삽입, 크로스사이트 스크립트(XSS) 등의 공격을 유발할 수 있다.

 

 

LDAP 삽입

 

■ 개요

 

공격자가 외부 입력을 통해서 의도하지 않은 LDAP(LightweightDirectoryAccessProtocol) 명령어를 수행할 수 있다.


즉, 웹 응용프로그램이 사용자가 제공한 입력을 올바르게 처리하지 못하면, 공격자가 LDAP 명령문의 구성을 바꿀 수 있다. 이로 인해 프로세스가 명령을 실행한 컴포넌트와 동일한 권한(Permission)을 가지고 동작하게 된다.


외부 입력값을 적절한 처리 없이 LDAP 쿼리문이나 결과의 일부로 사용하는 경우, LDAP 쿼리문이 실행될 때 공격자는 LDAP 쿼리문의 내용을 마음대로 변경할 수 있다. Python에는 Python-ldap 및 ldap3라는 두 개의 라이브러리가 있다. ldap3가 python-ldap 보다 더 현대적인 라이브러리 이다. 

 

ldap3 모듈은 Python 2.6부터 모든 Python 3 버전에 호환된다. ldap3에서는 좀 더 Python적인 방식으로 LDAP서버와 상호 작용할 수 있는 완전한 기능의 추상화 계층이 포함되어 있다. python-ldap은 OpenLDAP에서 만든 Python2의 패키지로 Python3에서는 ldap3 라이브러리를 사용하는 것이 권장된다.

 

 

■ 안전한 코딩 기법

 

다른 삽입 공격과 마찬가지로 LDAP 삽입에 대한 기본적인 방어 방법은 적절한 유효성 검사이다.
⦁올바른 인코딩(Encoding) 함수를 사용하여 모든 변수 이스케이프(Escape)
⦁화이트리스트 방식의 입력 값 유효성 검사
⦁사용자 비밀번호와 같은 민감한 정보가 포함된 필드 인덱싱
⦁LDAP 바인딩 계정에 할당된 권한 최소화

 

 

코드예제

 

사용자의 입력을 바로 LDAP 질의문에 사용하고 있으며 이 경우 권한 상승 등의 공격에 노출될 수 있다.

 

안전하지 않은 코드의 예
from ldap3 import Connection, Server, ALL
from django.shortcuts import render

def ldap_query(request):
# 외부 입력값으로 LDAP 쿼리문의 인자에 검증 없이 사용하면
# 안전하지 않다.
search_keyword = request.POST.get('search_keyword','')

dn = server.config['bind_dn']
password = server.config['password']

address = 'ldap.badSoruce.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, '/ldap_query_response.html', {'ldap':conn.entries})

 

사용자의 입력 중 LDAP 질의문에 사용될 변수를 이스케이프 하여 질의문을 실행 시 공격에 노출되는 것을 예방할 수 있다.

 

안전한 코드의 예
from ldap3 import Connection, Server, ALL
from ldap3.utils.conv import escape_filter_chars
from django.shortcuts import render

def ldap_query(request):
search_keyword = request.POST.get('search_keyword','')

dn = server.config['bind_dn']
password = server.config['password']

address = 'ldap.goodsource.com'
server = Server(address, get_info=ALL)
conn = Connection(server, dn, password, auto_bind=True )

# 사용자의 입력에 필터링을 적용하여 공격에 사용될 수 있는 문자를
# 이스케이프하고 있다
escpae_keyword = escape_filter_chars(search_keyword)
search_str = '(&(objectclass=%s))' % escpae_keyword

conn.search('dc=company,dc=com', search_str, attributes=['sn', 'cn', 'address', 'mail', 'mobile', 'uid'])
return render(request, '/ldap_query_response.html', {'ldap':conn.entries})

 

 

댓글

Designed by JB FACTORY