FlawOpen

flawopen.com/Python SQL Injection/SQLAlchemy

SQLAlchemy text()는 SQL Injection에 안전한가요?

참고 가이드
간단한 답변

바인딩 매개변수는 쿼리 양식의 봉인된 값 카드와 같습니다. SQLAlchemy는 SQL 문과 매개변수 매핑을 하위 DBAPI에 전달하므로 애플리케이션 코드가 구성하는 SQL 표현식에 값이 섞이지 않습니다. 데이터베이스별 바인딩은 DBAPI 드라이버가 처리하므로 전송 방식은 달라질 수 있습니다. text()는 SQL 텍스트를 받지만 이미 그 텍스트에 삽입된 값을 정제하거나 매개변수화하지는 않습니다.

취약 — 입력을 SQL에 보간
stmt = text(
  f"SELECT id FROM users WHERE id = {user_id}"
)
rows = conn.execute(stmt)
강화 — 값을 바인딩하고 SQL 구조 제한
stmt = text(
  "SELECT id FROM users WHERE id = :id"
)
rows = conn.execute(stmt, {"id": user_id})

# Bind values, not identifiers. Choose any
# selectable column from a fixed application map.
columns = {"name": users.c.name,
           "created": users.c.created_at}
column = columns.get(requested_sort, users.c.created_at)
stmt = select(users.c.id).order_by(column)
rows = conn.execute(stmt)

text()가 하는 일과 하지 않는 일

text()는 텍스트 SQL 구문을 만들 뿐, 입력이 이미 보간된 문자열을 정화하지 않습니다. SQL에 값 placeholder를 선언하고 Connection.execute() 또는 Session.execute()에 값을 별도로 전달하세요. SQLAlchemy Core 표현식 API는 적절한 경우 Python 리터럴 값을 바인딩하지만 텍스트 조각은 SQL 구문입니다. 매개변수는 테이블명, 컬럼명, 정렬 방향을 대신할 수 없습니다. 사용자가 선택할 수 있는 구조를 고정 SQLAlchemy 표현식에 매핑하세요. 매개변수화는 SQL Injection을 막지만 권한 확인이나 업무 규칙 검증을 대체하지 않습니다.

코드베이스 감사 방법

rg -n 'text\(|\.execute\(' --glob '*.py' .

자주 묻는 질문

SQLAlchemy Core 및 ORM 쿼리 빌더는 항상 안전한가요?

일반적인 표현식 구성에서는 Python 값을 바인딩하지만, 안전성은 문을 구성하는 방식에 달려 있습니다. 텍스트 SQL, 리터럴 SQL 구성, 동적 식별자도 검토하세요. 입력을 연결한 뒤 SQL 문자열을 안전하게 만드는 API는 없습니다.

참고 자료

함께 보기 SQL 인젝션(CWE-89): 동작 원리와 언어별 방어 방법 — flawopen.com sqlx의 컴파일 시 쿼리 검사가 SQL 인젝션을 막나요? 저장 프로시저는 SQL 인젝션을 막나요? TypeORM QueryBuilder는 SQL Injection에 안전한가요? Django ORM SQL Injection: 안전한 패턴 Doctrine ORM SQL 인젝션: 안전한 쿼리 EF Core FromSqlRaw: 안전한 SQL 매개변수화