최근 수정 시각 : 2025-01-22 20:24:51

SQL injection

SQL 주입에서 넘어옴
1. 개요2. 구현
2.1. 웹사이트에서의 예시
3. 방어
3.1. SQL 파라미터 바인딩 사용3.2. 입력 값 검증 및 필터링 (예외 처리)3.3. ORM 사용3.4. 기타
4. 이 기법을 이용한 해킹 사례

1. 개요

SQL 인젝션(SQL 삽입, SQL 주입)은 코드 인젝션의 한 기법으로 클라이언트의 입력값을 조작하여 서버의 데이터베이스를 공격할 수 있는 해킹 기법이다.

사용자가 입력한 데이터를 프로그램이 SQL 문법으로 인식했을 때 발생한다. 특수문자 몇 자로도 발생할 수 있는 쉬운 공격 난이도에 비해 어마어마한 피해를 발생시키기 때문에 정보보안에서는 해킹의 대표 예시로 등장한다.[1]

2. 구현

파일:RmfbEsZ.jpg
과속방지 카메라에 SQL injection 하기[2]

프로그램이 SQL 코드를 통해 데이터 처리를 할 것으로 예상되는 문자열 입력값에 SQL 문법으로 해석될 수 있는 문자열을 삽입하고, 이를 프로그램이 처리하도록 한다. 먼저 프로그램이 SQL을 사용하고 있어야 하며, SQL 문법에 대한 별다른 예외 처리를 하지 않고 있으면 구현될 수 있다. 주로 다음과 같은 과정을 따른다.
  • 프로그램에 입력이 가능한 필드(표, 비밀번호 란, URL 등)를 찾는다.
  • 프로그램이 SQL 문법으로 해석할 만한 문자열을 작성한다. 이 문자열은 반드시 True(참) 또는 데이터를 반환하도록 하거나, 데이터를 삭제하거나, 변조하는 코드일 수 있다.
  • 작성한 코드를 입력이 가능한 필드에 집어넣고 프로그램을 실행한다.

프로그램이 입력값을 SQL 문법으로 인식하면 공격에 성공한다. 원래 SQL 코드는 사용자가 서버에 직접 입력할 수 있어선 안 되지만, 개발 편의상 작성한 코드가 상용 환경에도 남아있거나, 적절한 예외 처리가 되어 있지 않을 경우 SQL 삽입이 가능해질 수 있다.

2.1. 웹사이트에서의 예시

대다수의 웹사이트에서 로그인 폼에 아이디와 비밀번호를 입력하고 로그인하면 입력한 값이 서버로 전송되어 처리되는데, 이 과정에서 서버가 데이터베이스를 조회하여 사용자 정보가 일치한다면 로그인에 성공하게 된다. 여기서 데이터베이스에 값을 조회하기 위해 사용되는 언어를 SQL이라고 한다.

먼저 클라이언트에는 아래와 같은 로그인 폼을 표시한다고 가정한다.
아이디: (아이디를 입력하세요)
비밀번호: (비밀번호를 입력하세요)

다음으로 서버 측 프로그램이 로그인을 수행하기 위해 작성된 SQL 코드가 다음과 같이 작성되었다고 가정한다.
SELECT user FROM user_table WHERE id='입력한 아이디' AND password='입력한 비밀번호';
  • 이 명령은 입력한 아이디와 비밀번호가 데이터베이스상에 저장된 아이디(id)와 비밀번호(password)와 같을 경우에만 'user_table'에서 'user' 데이터를 가져온다.[주의]

사용자가 아이디에 '나무', 비밀번호에 '위키'를 입력하고 로그인을 시도하면 서버는 아래와 같은 SQL 코드를 실행할 것이다.
SELECT user FROM user_table WHERE id='나무' AND password='위키';

일반적인 상황에서는 이 코드가 아무런 문제 없이 사용자 정보를 가져오겠지만, 공격자가 아이디 또는 비밀번호에 SQL 문법으로 해석될 수 있는 특수문자를 입력하면 프로그램이 의도하지 않은 방향으로 작동할 수 있다.

공격자는 아래와 같이 입력하고 로그인을 시도할 수 있다.
아이디: admin
비밀번호: ' OR '1' = '1

위와 같은 입력값을 통해 서버는 아래 코드를 실행할 것이다.
SELECT user FROM user_table WHERE id='admin' AND password=' ' OR '1' = '1';
  • 여기서 and와 or은 '그리고, 또는'이 아닌 A와 B값이 모두 참이면 True(참 값), A와 B값 중 하나라도 특정 값이 참이면 True를 출력하는 연산자다.
  • 비밀번호 입력값과 마지막 구문을 살펴보면, 따옴표를 올바르게 닫으며 password=' '를 만듦과 동시에 SQL 구문 뒤에 ' OR '1' = '1'을 붙였다. WHERE 뒤에 있는 구문을 간단히 축약하면 false AND false OR true로 정리할 수 있는데, SQL 문법에서 AND 연산은 OR보다 연산 우선순위가 높기 때문에 해당 구문의 연산 값은 true가 되어 올바른 값으로 판단하고 실행하게 된다.
  • 즉, 비밀번호를 몰라도 ' OR '1' = '1 구문으로 인해 마치 올바른 비밀번호를 입력한 것처럼 작동하게 된다.

3. 방어

3.1. SQL 파라미터 바인딩 사용

사용자 입력을 안전하게 처리하기 위해서는 무엇보다 SQL 쿼리문과 데이터를 분리하는 것이 바람직하다. 사용자 입력과 SQL 쿼리문을 매 요청마다 결합해서 실행하는 방식은 최적화 차원에서 비효율적일 뿐만 아니라, 잠재적인 보안 위협에서 절대 벗어날 수 없기 때문이다.

아래와 같이 구현하면 단순 특수문자 삽입으로부터 SQL 코드를 보호할 수 있다.
$stmt = $pdo->prepare('SELECT * FROM users WHERE username = ? AND password = ?');

사용자 입력과 함께 처리할 때는 이렇게 사용한다.
$stmt->execute([$username, $password]);

3.2. 입력 값 검증 및 필터링 (예외 처리)

사용자 입력 값에 대해 허용된 패턴만 받도록 검증하거나 특수 문자를 제거하는 방법이다.
  • 숫자만 입력 가능한 경우 int 형식으로 변환한다. 단, 숫자 길이에 따라 오버플로우가 발생할 수 있으니 유의해야 한다.
  • 정규식을 사용하여 예상하지 않은 입력을 차단한다.
  • 입력 값의 최대 길이를 제한한다.

단, 이 방식은 데이터 처리를 복잡하게 만들고 코드 재사용성을 떨어트릴 수 있으므로 신중히 도입해야 한다.

3.3. ORM 사용

데이터베이스 작업을 직접 SQL로 처리하지 않고, Hibernate, SQLAlchemy, Django ORM와 같은 ORM(Object-Relational Mapping)을 사용해 데이터를 처리할 수 있다. ORM은 데이터베이스를 관리할 때 SQL 문법 대신 개발에 사용하는 언어를 그대로 데이터베이스 관리에 사용할 수 있게 해주므로 개발 편의성이 증가한다. 단, 일부 ORM 라이브러리는 지연 시간이 늘어나거나 SQL의 모든 기능을 지원하지 않을 수 있으므로 특정한 요구 조건이 있는 경우 주의해야 한다.

3.4. 기타

  • 최소 권한 원칙(Zero-Trust) 지키기. 중대한 SQL 삽입 공격에 대응하기 위해서는 데이터베이스 계정에 최소 권한만 부여하여 읽기/쓰기 권한을 필요한 테이블에만 제한하는 것이 좋다.
  • SQL 오류 메시지는 가능한 한 숨길 것. SQL 오류를 직접 전달하는 대신 일반적인 에러 메시지를 반환하거나, 사용자에게 친화적인 에러 화면 제공할 수 있다. 친화적인 오류는 사용자 경험에도 긍정적이다.

4. 이 기법을 이용한 해킹 사례

  • 기사
    조셉 타타로라는 보안 연구원이 교통 법규 벌금을 내지 않기위해 Null이란 번호판을 이용한적이 있었는데 의도와는 반대로 차량번호가 입력되지 않은 벌금이 죄다 타타로에게 가는 희한한 상황이 연출된 적이 있다. 이경우는 타타로의 차 번호판을 문자열 "NULL"이 아닌 프로그래밍값 NULL로 처리하면서 번호가 없어 NULL로 된 벌금이 전부 타타로에게 간것. 어찌저찌 청구 문제가 해결된 후에도 조셉 타타로 본인은 애착이 생긴 건지 아직도 NULL 번호판을 쓴다고 한다.


[1] 보안회사 Imperva가 2012년에 발표한 보고서에 따르면 월평균 4회 가량의 SQL 인젝션 공격이 일어난다고 한다. OWASP에서도 수년 동안 인젝션 기법이 보안 위협 1순위로 분류되었던 만큼 주목할 필요가 있다. [2] DROP DATABASE 구문은 데이터베이스를 삭제하는 명령어다. 물론 차량 번호 인식 프로그램은 입력값으로 숫자와 로마자만 받아야 하니 이게 먹힐 가능성은 없어야 한다. 차량은 르노 메간. [주의] 여기서는 패스워드를 평문으로 비교하는데 사실 이는 예제를 간단히 하기 위한 것이므로 실제로 이렇게 처리해선 안 된다. 테스트가 아닌 일반 사이트에서 이렇게 운영하면 개인정보보호법 29조 (개인정보처리자는 개인정보가 분실·도난·유출·위조·변조 또는 훼손되지 아니하도록 내부 관리계획 수립, 접속기록 보관 등 대통령령으로 정하는 바에 따라 안전성 확보에 필요한 기술적·관리적 및 물리적 조치를 하여야 한다)에 따라 처벌받을 수 있다. 비밀번호는 반드시 PBKDF2 이상의 보안성을 가지는 해시 함수로 해싱해야 안전하다.