flawopen.com/참고 자료/FastAPI SQL 인젝션
FastAPI는 기본 설정만으로 SQL 인젝션을 막나요?
Python 및 API 가이드
요약
Pydantic은 값이 선언된 입력 유형과 일치하는지 확인하지만 SQL을 다시 작성하거나 Python 문자열을 데이터베이스 매개변수로 바꾸지는 않습니다. 검증된 name: str도 호출자가 제어하는 텍스트입니다. 검증은 소포의 라벨을 확인하는 일이고, 매개변수 바인딩은 값을 SQL 지시문과 분리해 봉인하는 일이라고 생각하세요. SQL 템플릿은 고정하고 값은 SQLAlchemy를 통해 따로 전달합니다.
FastAPI의 취약한 패턴과 안전한 패턴
취약: 보간으로 SQL 텍스트가 바뀜
# A string type check does not make input safe inside SQL syntax
@app.get("/users")
def get_users(name: str, db: Session = Depends(get_db)):
query = text(f"SELECT * FROM users WHERE name = '{name}'")
return db.execute(query).fetchall()
안전: SQLAlchemy가 값을 별도로 바인딩
# :name is a bind parameter; the value is passed separately
@app.get("/users")
def get_users(name: str, db: Session = Depends(get_db)):
query = text("SELECT * FROM users WHERE name = :name")
return db.execute(query, {"name": name}).fetchall()
매개변수 바인딩이 다루지 않는 것
바인딩 매개변수는 데이터 값을 나타내며 테이블명, 열 이름, SQL 연산자, 정렬 방향을 나타내지 않습니다. 요청에서 정렬 필드를 고르게 해야 한다면 선택지를 고정된 SQLAlchemy 열 표현식 허용 목록에 매핑하세요. 요청 원문을 SQL에 이어 붙이면 안 됩니다. 매개변수화는 권한 확인을 대신하지도 않습니다. 호출자가 읽을 수 있는 행을 제한하고 데이터베이스 계정에는 해당 엔드포인트에 필요한 권한만 부여하세요.
예방 체크리스트
- ✓요청 데이터를 SQLAlchemy
text()또는 원시 데이터베이스 실행 문자열에 보간하지 않습니다. - ✓이름이 있는 바인딩 매개변수를 사용하고 값을 별도로 전달합니다. 예:
db.execute(query, {"name": name}). - ✓동적 테이블, 열 또는 정렬 선택은 알려진 SQLAlchemy 표현식의 고정 허용 목록에 매핑합니다.
- ✓행 단위 권한을 별도로 확인하고 데이터베이스 계정에는 엔드포인트에 필요한 권한만 부여합니다.
- ✓쿼리를 명확히 표현할 수 있으면 SQLAlchemy
select()를 우선 사용합니다. ORM을 사용해도 안전하지 않은 원시 SQL이 안전해지지는 않습니다.