설명
LDAP 필터 인젝션은 신뢰할 수 없는 데이터가 RFC 4515에 따른 이스케이프 처리 없이 검색 필터에 삽입될 때 발생합니다. 공격자는 필터 연산자나 와일드카드를 추가해 조건식을 변경하여 인증을 우회하거나 애플리케이션이 노출하려 하지 않은 디렉터리 항목을 반환하게 할 수 있습니다.
잠재적 영향
- 사용자 검색 조건이나 인증 조건을 우회할 수 있습니다.
- 디렉터리 사용자, 그룹, 메일 주소 같은 민감한 정보가 노출될 수 있습니다.
- 광범위하거나 계산 비용이 큰 필터로 LDAP 서버 부하를 높일 수 있습니다. 실제 영향은 디렉터리 접근 제어와 검색 제한에 따라 달라집니다.
해결 방법
- LDAP 필터 구조와 속성 이름을 고정하고, 신뢰할 수 없는 데이터는 어설션 값(assertion value) 위치에만 넣습니다.
- python-ldap에서는 각 어설션 값을
ldap.filter.escape_filter_chars로 이스케이프하거나, 신뢰할 수 있는 고정 템플릿과 값 목록을ldap.filter.filter_format에 분리하여 전달합니다.filter_format의 첫 번째 인수인 템플릿을 외부 입력으로 만들면 안 됩니다. - ldap3에서는 각 어설션 값을 검색 필터에 삽입하기 전에
ldap3.utils.conv.escape_filter_chars로 이스케이프합니다. - 검색 필터 이스케이프와 DN 이스케이프는 서로 다릅니다. DN을 구성할 때는 해당 RFC 4514 값에
ldap.dn.escape_dn_chars또는ldap3.utils.dn.escape_rdn을 사용합니다. - 필요한 경우 업무 규칙에 따른 허용 목록과 길이 제한을 적용하고 최소 권한 계정으로 바인드합니다. 이러한 통제는 문맥에 맞는 이스케이프를 보완하며 대체하지 않습니다.
예시
변경 전
python
import ldap
from flask import request
def bad_search():
conn = ldap.initialize("ldaps://directory.example.com")
username = request.args.get("user")
query = "(uid=%s)" % username
return conn.search_s("ou=users,dc=example,dc=com", ldap.SCOPE_SUBTREE, query)
변경 후
python
import ldap
from ldap.filter import filter_format
from flask import request
def safe_search():
conn = ldap.initialize("ldaps://directory.example.com")
username = request.args.get("user")
query = filter_format("(uid=%s)", [username])
return conn.search_s("ou=users,dc=example,dc=com", ldap.SCOPE_SUBTREE, query)
설명:
- 변경 전: 사용자 입력을 LDAP 필터 문자열에 직접 삽입합니다.
- 변경 후: 애플리케이션이 필터 템플릿을 고정하고,
filter_format이 별도로 전달된 어설션 값에 RFC 4515 이스케이프를 적용합니다.
적용 시 주의 사항
필터 이스케이프는 연결의 TLS 검증, 바인드 계정의 권한, 필수 입력값 검증을 대신하지 않습니다. 예시는 검색 필터 구성에 집중한 발췌이며 이러한 설정은 별도로 준비하세요. DN이나 다른 LDAP 표현식을 구성한다면 그 문맥에 맞는 이스케이프를 사용하세요.