FlawOpen

flawopen.com/Python의 SQL Injection/Django ORM

Django ORM은 기본적으로 SQL Injection을 막을까?

참고 페이지
핵심 답변

.filter(), .get(), .exclude() 같은 일반적인 Django QuerySet API는 SQL과 값을 분리하고 값을 데이터베이스 드라이버에 매개변수로 전달합니다. 이 보호가 모든 쿼리 작성 방식을 포괄하지는 않습니다. Raw SQL, 사용자 정의 표현식, 사용자가 선택하는 쿼리 구조는 별도로 검토해야 합니다.

Django QuerySet에서 값을 안전하게 전달하기

위험 — 입력을 raw SQL에 삽입
username = request.GET.get("u", "")
User.objects.raw(
    f"SELECT * FROM myapp_user WHERE username = '{username}'"
)
안전 — raw()의 params로 입력 바인딩
username = request.GET.get("u", "")
User.objects.raw(
    "SELECT * FROM myapp_user WHERE username = %s",
    [username],
)

보호 경계가 끝나는 지점

Model.objects.raw()

Manager.raw()는 전달된 SQL을 실행합니다. 사용자 제어 값은 params로 전달하고 placeholder를 따옴표로 감싸지 마세요. 예: User.objects.raw("SELECT * FROM users WHERE username = %s", [username]). f-string, % 포맷팅, 문자열 연결로 값을 SQL에 넣지 마세요. 매개변수는 값용이며 테이블명·컬럼명 같은 SQL 식별자용이 아닙니다.

connection.cursor() 직접 접근

데이터베이스에 직접 접근할 때는 cursor.execute(sql, params)를 사용하고 Django 문서의 placeholder 형식에 따라 값을 분리해 전달하세요. 값을 sql에 보간하지 마세요. RawSQL 및 Func 표현식도 검토하세요. 템플릿 컨텍스트와 키워드 인자는 매개변수로 바인딩되지 않고 SQL에 보간될 수 있습니다.

사용자 제어 필드 경로

.filter(**{field: value})의 사용자 제어 필드 경로가 자동으로 SQL Injection이 되는 것은 아닙니다. Django는 lookup 이름을 쿼리 구조로 해석합니다. 그래도 endpoint가 제공하면 안 되는 필드, 관계, lookup을 노출하거나 오류를 일으킬 수 있습니다. 외부 정렬·필터 선택을 허용된 모델 필드와 lookup의 좁은 allow-list로 변환하세요.

Django 쿼리 감사 방법

rg -n '(\.raw\(|RawSQL\(|\.extra\(|connection\.cursor\()' --glob '*.py' .
.raw(), RawSQL, .extra(), connection.cursor() 사용을 검색하세요. 각 결과에서 값의 흐름을 추적하고 바인딩 매개변수, 신뢰할 수 없는 SQL 조각, 동적 식별자·lookup 및 사용자 정의 Func 템플릿을 확인하세요.

자주 묻는 질문

extra()는 안전할까?

QuerySet.extra()는 Raw SQL 조각을 추가하는 기존 API입니다. 새 코드에서는 피하고 기존 where, select 인자를 주의 깊게 검토하세요. QuerySet 표현식을 우선 사용하고 Raw SQL이 필요하면 문서화된 params 인자로 값을 바인딩하세요.

Django REST Framework에도 적용될까?

Django REST Framework는 ORM의 SQL 매개변수화를 바꾸지 않습니다. view, serializer, viewset에서 만드는 쿼리에도 같은 규칙이 적용됩니다. 클라이언트가 제어하는 정렬·필터 필드도 allow-list로 제한하세요.

참고 자료

함께 보기 SQL 인젝션(CWE-89): 동작 원리와 언어별 방어 방법 — flawopen.com Doctrine ORM SQL 인젝션: 안전한 쿼리 EF Core FromSqlRaw: 안전한 SQL 매개변수화 FastAPI SQL 인젝션: Pydantic이 막는 것과 막지 못하는 것 GORM Raw SQL: Go SQL 인젝션 방지 따옴표 이스케이프만으로 SQL Injection을 막을 수 있을까? ORM만 쓰면 SQL 인젝션을 막기에 충분한가