API Security SQL Injection Validation
3줄 요약
- API 보안의 입력 경계는
요청값을 받을 때, 객체에 바인딩할 때, 쿼리와 출력에 사용할 때, 실패를 응답할 때, 반복 호출을 허용할 때마다 다시 생긴다.
- SQL Injection, Mass Assignment, 정보 노출, 자동화 남용은 모두 정상 API 모양으로 들어오지만 깨지는 지점은 서로 다르다.
- 방어는 Prepared Statement, allowlist validation, DTO 경계, 일반화된 오류 응답, endpoint별 rate limit를 조합하고 로그로 거부 이유를 복원할 수 있어야 한다.
핵심 정리
- SQL Injection 방어의 1차 선택지는 parameterized query다. 다만 컬럼명, 정렬 방향, 테이블명 같은 SQL 구조는 파라미터로 바인딩할 수 없으므로 allowlist가 필요하다.
- Input validation은 서버가 받을 수 있는 값의 문법과 업무 의미를 줄이는 일이다. Output encoding은 이미 저장된 값이 HTML, JavaScript, URL, JSON 같은 출력 문맥에서 코드로 해석되지 않게 하는 일이다.
- Mass Assignment는 JSON 필드가 엔티티의 민감 필드까지 자동 바인딩될 때 생긴다. 요청 DTO는 사용자가 바꿀 수 있는 필드만 포함해야 한다.
- 오류 응답은 사용자 행동을 안내해야 하지만 SQL, stack trace, class name, 내부 path, 계정 존재 여부를 설명하면 안 된다.
- Rate limit는 IP 하나로 끝나지 않는다. 계정, IP, device, endpoint, 비용 단위, 실패 횟수를 조합해야 인증번호 발송, 검색, 비밀번호 재설정, 결제 시도 남용을 줄일 수 있다.
- 운영 로그는 차단한 payload 원문이 아니라
event, principal, endpoint, reason, limitKey, traceId처럼 분석 가능한 필드를 남긴다.
하위 문서 연결
-
- SQL Injection 공격과 Prepared Statement: 값은 bind parameter로 넘기고, SQL 구조 선택은 allowlist로 제한한다.
-
- Input Validation과 Output Encoding: validation과 encoding을 같은 방어로 섞지 않고 입력 시점과 출력 시점의 책임을 나눈다.
-
- Mass Assignment와 DTO 경계: 요청 DTO, domain method, 관리자 전용 endpoint 분리로 민감 필드 바인딩을 막는다.
-
- Error Message 정보 노출 방지: 클라이언트 응답은 일반화하고 서버 로그는 trace id로 상세 원인을 추적한다.
-
- Rate Limit과 Abuse 방어: 단순 트래픽 제한이 아니라 비즈니스 기능 남용과 비용 폭증까지 제한한다.
헷갈리는 지점
- Prepared Statement가 있으면 모든 SQL Injection이 끝났다고 생각하기 쉽다.
- 값 바인딩은 쿼리 의도를 바꾸는 payload를 막지만
order by ${sort} 같은 구조 결합은 여전히 위험하다.
- 동적 조건, native query, report query, 관리자 검색 API를 별도로 리뷰한다.
- 검증을 강하게 하면 XSS도 자동으로 막힌다고 생각하기 쉽다.
- validation은 입력 범위를 줄이는 방어고, encoding은 출력 문맥에서 코드 해석을 막는 방어다.
- 저장된 값이 다른 화면, 메일, 관리자 콘솔, CSV로 나갈 수 있으면 출력 시점 방어를 다시 본다.
- DTO가 있으면 Mass Assignment가 자동으로 사라진다고 생각하기 쉽다.
- DTO에
role, point, emailVerified, ownerId 같은 필드가 있으면 여전히 공격자가 값을 보낼 수 있다.
- 사용자용 DTO와 관리자용 DTO를 분리하고 예상 밖 필드 테스트를 추가한다.
- 429만 반환하면 abuse 방어가 된다고 생각하기 쉽다.
- 어떤 key로 제한했는지, 정상 사용자의 회복 경로가 있는지, 우회 패턴이 로그에 남는지가 더 중요하다.
확인 질문
- SQL Injection에서 Prepared Statement만으로 부족한 입력은 무엇인가?
- 컬럼명, 정렬 방향, 테이블명, SQL fragment처럼 쿼리 구조를 바꾸는 입력이다. 이런 값은 allowlist로 선택해야 한다.
- Input validation과 output encoding의 책임은 어떻게 다른가?
- validation은 서버가 받을 입력 범위를 제한하고, encoding은 출력 문맥에서 저장값이나 요청값이 코드로 실행되지 않게 한다.
- API abuse 방어를 설계할 때 IP 외에 어떤 기준을 함께 봐야 하는가?
- 계정, device, endpoint, 실패 횟수, 리소스 비용, 외부 API 비용, 업무 흐름 단위다.