본문으로 건너뛰기
SDETRole
SDETRole

용어집 · 보안

SQL 인젝션

영어: SQL injection

다른 이름: SQLi, SQL 삽입, SQL 인젝션 공격

정의

사용자 입력이 SQL 쿼리에 그대로 이어 붙여져 공격자가 쿼리 로직을 바꿔 데이터를 조회·변경·삭제할 수 있는 취약점입니다.

SQL 인젝션(SQLi)은 애플리케이션이 사용자 입력을 쿼리 문자열에 그대로 붙여 SQL 문을 만들 때 발생합니다. 입력값에 SQL 구문이 들어 있으면 데이터베이스는 그것을 쿼리의 일부로 실행합니다. 쿼리와 데이터베이스 권한에 따라 공격자는 로그인을 우회하거나, 다른 사용자의 데이터를 읽거나, 레코드를 수정하거나, 최악의 경우 서버에서 명령을 실행할 수도 있습니다. OWASP Top 10 2021에서는 A03 Injection에 속합니다.

예시

취약한 Java 코드입니다.

String sql = "SELECT * FROM users WHERE email = '" + email + "'";
ResultSet rs = conn.createStatement().executeQuery(sql);

email이 ' OR '1'='1이면 쿼리는 다음과 같이 바뀝니다.

SELECT * FROM users WHERE email = '' OR '1'='1'

조건이 항상 참이 되므로 쿼리는 모든 사용자를 반환합니다. 해결책은 파라미터화된 쿼리(parameterized query)입니다. 입력값을 SQL 텍스트와 분리해서 전송하므로 입력이 쿼리 구조를 바꿀 수 없습니다.

PreparedStatement ps = conn.prepareStatement("SELECT * FROM users WHERE email = ?");
ps.setString(1, email);
ResultSet rs = ps.executeQuery();

테스터가 확인하는 항목

서면 승인을 받은 상태에서, 테스트 환경에서만 수행합니다.

  • 구문을 깨뜨려 봅니다. 쿼리에 도달할 수 있는 모든 텍스트 필드, URL 파라미터, 헤더, JSON 값에 작은따옴표 ' 하나를 넣어 봅니다. 500 오류, 데이터베이스 오류 메시지, 결과 건수의 변화가 나타나면 입력이 이스케이프되지 않은 채 SQL에 도달하고 있을 가능성이 큽니다.
  • 로직을 바꿔 봅니다. value' AND '1'='1과 value' AND '1'='2의 응답을 비교합니다. 일반 값으로는 설명되지 않는 차이가 있다면 입력이 SQL로 해석되고 있는 것입니다.
  • 눈에 덜 띄는 입력도 확인합니다. 정렬 컬럼, 필터 필드, 검색창, 리포트 파라미터는 동적으로 구성되는 경우가 많습니다. 컬럼 이름은 파라미터로 바인딩할 수 없기 때문입니다.
  • 오류 처리를 확인합니다. 응답에 데이터베이스 오류, 테이블 이름, 스택 트레이스가 노출된다면 그 자체로 결함입니다.

sqlmap 같은 도구로 더 깊은 탐색을 자동화할 수 있지만, 데이터를 수정하거나 삭제할 수 있으므로 명시적으로 테스트 허가를 받은 시스템에만 실행해야 합니다.

검증해야 할 방어 수단

모든 곳에서 파라미터화된 쿼리나 ORM을 올바르게 사용하는지, 정렬 컬럼 같은 동적 식별자에 허용 목록(allow-list)을 적용하는지, 데이터베이스 계정이 최소 권한으로 운영되는지, 오류 메시지가 일반적인 내용만 보여 주는지 확인합니다. 입력값 검증도 도움이 되지만 파라미터화를 대체하지는 못합니다.

SDETRole 전체에서 검색할 내용을 입력하세요.

Pagefind 전문 검색 · 브라우저에서 실행됩니다 검색 페이지 열기 →