SQL 인젝션 스캐너 선택 방법
Yuta Matsuyama
TECHFUND 주식회사 보안 연구원
업데이트:
대상 독자: SQL 인젝션 테스트 도구를 선택하는 개발 및 보안 팀.
스캐너를 선택하기 전에 검사 진입점 정하기
예를 들어 검색 폼에 입력한 값이 그대로 SQL 문의 일부로 조합된다고 가정해 보겠습니다. 동적 검사는 실제로 요청을 보내고 응답의 차이 등을 통해 문제를 찾습니다. 코드 분석은 값이 어디서 들어와 어떤 쿼리로 전달되는지를 추적합니다.
동적 검사는 화면이나 API에 접근할 수 없으면 검사할 수 없습니다. 코드 분석도 지원 언어나 프레임워크, 분석 대상 설정에 따라 문제를 놓칠 수 있습니다. 한쪽의 탐지 결과가 0건이라고 해서 다른 쪽이 불필요해졌다고 판단할 수는 없습니다.
대표적인 도구와 용도별 선택
ZAP: 웹 앱 전체를 확인하고 싶을 때 고려할 만한 OSS입니다. SQL 인젝션 능동 스캔 규칙이 있으며, 다른 웹 취약점도 함께 검사할 수 있습니다. 다만 ZAP Baseline은 기본적으로 수동적 스캔을 수행하므로, 이것을 실행한 것만으로 SQL 인젝션 능동 검사를 마쳤다고 할 수는 없습니다.
sqlmap: 특정 입력 지점이 의심스러워 SQL 인젝션을 집중적으로 검증하고 싶을 때 사용하는 OSS입니다. 탐지뿐 아니라 악용을 자동화하는 기능도 있으므로, 허용 범위를 정하고 영향을 최소화할 수 있는 환경에서 사용해야 합니다.
Burp Suite Professional: HTTP 요청을 확인하면서 스캐너와 수동 검증을 병행하려는 담당자에게 적합합니다. 자동 스캐너는 유료 버전인 Professional 등에 포함되며, 무료 Community Edition에는 포함되지 않습니다.
Wapiti: 명령줄에서 웹 앱을 블랙박스 방식으로 검사하는 OSS입니다. 공식 자료에서는 오류, 참·거짓 값, 시간 차이를 활용한 SQL 인젝션 검사와 OpenAPI 파일을 이용한 API 스캔을 안내합니다. SPA나 복잡한 인증이 포함된 대상에서 필요한 경로에 접근할 수 있는지는 개별적으로 검증하세요.
모두 실행 중인 앱에 요청을 보내는 도구입니다. 화면뿐 아니라 인증 후 접근하는 API, 관리 화면, 사용자별 권한까지 포함해 어디까지 접근했는지를 결과와 함께 기록해야 합니다. 소스 코드를 이용한 정적 분석은 별도의 선택지로 병행합니다.
도입할 때는 탐지 건수와 접근 범위를 모두 비교하기
동일한 스테이징 환경에 알려진 문제가 있는 입력과 안전하게 매개변수화된 입력을 준비해 비교합니다. 전자를 찾아낼 수 있는지뿐 아니라 후자를 문제로 잘못 판단하지 않는지도 확인합니다. 인증이 만료되어 검사가 도중에 멈추지는 않았는지, JSON API를 포함해 필요한 진입점을 순회할 수 있었는지도 확인하세요.
스캔은 검증용 데이터나 가용성에 영향을 줄 수 있습니다. 대상 소유자에게 명시적인 허가를 받고, 대상 범위, 실행 시간, 부하, 제외할 작업에 합의한 뒤, 가능하면 운영 환경과 분리된 환경에서 시험합니다.
MOVEit 사례를 바탕으로 공개 경로도 확인하기
NVD에 기록된 MOVEit Transfer의 CVE-2023-34362에서는 SQL 인젝션으로 인해 인증되지 않은 공격자가 DB에 접근할 가능성이 있으며, 2023년 5~6월에 악용된 사실도 기재되어 있습니다. 개발할 때는 로그인 후 처리뿐 아니라 공개 경로도 확인해야 합니다. 아래는 TypeScript와 node-postgres를 사용한 가상의 교육용 예제이며, MOVEit의 구현이나 해당 CVE를 재현하는 코드가 아닙니다. 검사는 허가받은 대상으로만 제한하세요.
문제를 찾았다면 값과 SQL 구조 분리하기
수정의 기본은 외부에서 들어온 값을 SQL 문자열에 이어 붙이지 않고 매개변수로 전달하는 것입니다. 다만 정렬 순서나 테이블 이름처럼 SQL 구조 자체에 해당하는 부분은 값 바인딩만으로 처리할 수 없는 경우가 있습니다. 이때는 앱에서 미리 마련한 고정된 선택지 중에서 고릅니다.
다음 예제에서는 검색값을 바인딩하고, 정렬 순서는 두 개의 고정 쿼리 중에서 선택합니다. 여기에 더해 DB 사용자의 권한을 필요한 최소한으로 제한하고, 사용자가 해당 데이터를 볼 권한이 있는지도 별도로 확인합니다. 수정 후에는 원래 지적된 문제가 해결되었는지와 일반적인 검색이 정상적으로 동작하는지를 다시 검증합니다.
import type { Pool } from "pg";
export async function findProducts(
db: Pool, name: string, sort: string,
) {
const queries = {
newest: "SELECT id, name FROM products WHERE name = $1 ORDER BY created_at DESC, id DESC LIMIT 50",
oldest: "SELECT id, name FROM products WHERE name = $1 ORDER BY created_at ASC, id ASC LIMIT 50",
} as const;
if (sort !== "newest" && sort !== "oldest") {
throw new Error("Invalid sort");
}
return db.query(queries[sort], [name]);
}- 사용자가 검색값을 입력
- 애플리케이션이 값을 $1에 바인딩
- 애플리케이션이 고정 쿼리와 값을 데이터베이스에 전달하여 실행
ORDER BY 같은 SQL 구조는 허용된 고정 쿼리에서 선택합니다. 사용자 인가와 데이터베이스 최소 권한은 별도로 필요하며, 이 그림만으로 보안이 보장되지는 않습니다.
자주 묻는 질문
스캐너가 SQL 인젝션이 없음을 보장하나요?
보장할 수 없습니다. 검사 범위, 설정, 접근 가능한 화면에 따라 탐지할 수 있는 범위가 달라집니다. 코드 검토도 병행하세요.
운영 중인 애플리케이션을 테스트해도 되나요?
명시적인 허가와 합의된 범위가 필요합니다. 동적 검사는 데이터나 가용성에 영향을 줄 수 있으므로 가능한 한 통제된 환경을 사용하세요.
출처 및 참고 자료
Hi AUDIT Agent가 돕는 방법
Hi AUDIT Agent로 코드의 데이터 흐름과 발견 위치, 수정안을 확인할 수 있습니다. 대상 환경의 SQL 인젝션 지원 범위를 확인하고 사람이 결과를 재검증하세요.
Hi AUDIT Agent 가입하기