mir.pe (일반/어두운 화면)
최근 수정 시각 : 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 문법에 대한 별다른 예외 처리를 하지 않고 있으면 구현될 수 있다. 주로 다음과 같은 과정을 따른다.

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

2.1. 웹사이트에서의 예시

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

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

다음으로 서버 측 프로그램이 로그인을 수행하기 위해 작성된 SQL 코드가 다음과 같이 작성되었다고 가정한다.
SELECT user FROM user_table WHERE id='입력한 아이디' AND password='입력한 비밀번호';

사용자가 아이디에 '나무', 비밀번호에 '위키'를 입력하고 로그인을 시도하면 서버는 아래와 같은 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';

3. 방어

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

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

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

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

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

사용자 입력 값에 대해 허용된 패턴만 받도록 검증하거나 특수 문자를 제거하는 방법이다.
단, 이 방식은 데이터 처리를 복잡하게 만들고 코드 재사용성을 떨어트릴 수 있으므로 신중히 도입해야 한다.

3.3. ORM 사용

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

3.4. 기타

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



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