2018.02.28

'웹 보안의 시작과 끝' SQL 인젝션의 정의와 대응방법

J.M. Porup | CSO
SQL 인젝션(SQL injection, SQLi)은 웹 애플리케이션 데이터베이스를 완전히 통제할 수 있는, 비교적 단순한 웹 애플리케이션 보안 공격이다. 1998년에 처음 발견된 이후 현재까지 인터넷에서 웹 애플리케이션을 괴롭히고 있다. 심지어 OWASP(The Open Web Application Security Project)의 보안 위협 순위 톱 10을 보면, SQL 인젝션이 웹 애플리케이션 최악의 위협으로 올라와 있다.



다행인 것은 SQL 인젝션이 공격자와 방어자 모두에게 매우 쉽다(?)는 것이다. 너무 쉬워서 첨단 NSA 쉐도우 브로커(Shadow Broker) 키트도 필요없다. 3살짜리도 할 수 있다. 동시에 이 어린애 장난 같은 스크립트와 위험을 완화하기 위해 웹 애플리케이션을 고치기도 너무 쉽다. 오히려 이를 수정하지 않는 것이 중대한 과실로 비치고 있다.

SQL 인젝션의 정의와 유형
SQL 인젝션의 유형은 여러 가지지만 핵심은 하나다. 공격자가 임의의 SQL을 웹 애플리케이션 데이터베이스 쿼리(Query)에 삽입하는 것이다.

가장 간단한 형태의 SQL 인젝션은 사용자 입력을 통한 것이다. 웹 애플리케이션은 일반적으로 서식을 통해 사용자 입력을 받아들인다. 이후 프런트 엔드(Front End)가 처리를 위해 백엔드(Back-end) 데이터베이스로 전달한다. 이 과정에서 웹 애플리케이션이 사용자 입력의 문제가 되는 곳을 걸러내지 못하면 해커가 원하는 SQL을 백엔드 데이터베이스에 입력해 데이터베이스의 내용을 삭제, 복사 또는 수정할 수 있다.

또한 공격자는 쿠키(Cookies)를 수정해 웹 애플리케이션의 데이터베이스 쿼리에 악영향을 끼칠 수 있다. 쿠키는 고객 상태 정보를 로컬에 저장하는데, 웹 애플리케이션은 일반적으로 쿠키를 불러와 해당 정보를 처리한다. 악의적인 사용자 또는 악성코드는 이 쿠키를 수정해 특정 SQL을 백엔드 데이터베이스에 입력할 수 있다.

HTTP 헤더(Header) 등의 서버 변수 또한 SQL 인젝션 공격 벡터로 사용된다. 임의의 SQL이 포함된 위조 헤더를 웹 애플리케이션이 걸러 내지 못하면 이 코드가 그대로 데이터베이스에 입력된다. 2차 SQL 인젝션 공격도 있다. 곧바로 실행되지 않고 나중에 실행되므로 가장 교활하다. 즉각적인 공격을 막기 위해 취약점을 제대로 제거하는 개발자도 2차 SQL 인젝션에 당하는 경우가 종종 있다.

SQL 인젝션 방법은?
SQL 인젝션의 역사는 꽤 길다. 이미 오래 전부터 자동화된 작업이기도 하다. SQL닌자(SQLninja), SQL맵(SQLmap) 및 하비즈(Havij) 등의 툴로 웹 애플리케이션을 손쉽게 테스트할 수 있다. 반면 이는 공격자에게도 마찬가지로 간단하다. 10년 전, 한 SQL 인젝션 웜(Worm)이 인터넷에서 난동을 부린 적이 있다. 그러나 현재도 크게 달라진 것은 없다. SQL 인젝션을 하나의 문제로 널리 인식하고 있지만 많은 웹 애플리케이션이 여전히 취약하다.

그래서 자동화된 테스트 툴이 한 대안이다. 이를 통해 손쉬운 공격 대상을 찾는 해커보다 한발 앞서 대비할 수 있다. SQL맵 등의 툴을 이용해 웹 애플리케이션 침투 테스트를 진행하는 것이 가장 간편하다. SQL맵은 현재 사용하는 거의 모든 주요 데이터베이스를 지원하며 알려진 대부분의 SQL 인젝션 취약성을 감지한다. 이들 툴은 입력 사항을 정리 테스트하고 대비책이 제대로 작동하고 있는지 검증한다.


SQL 인젝션 공격 사례
기본적인 SQL 인젝션 공격을 살펴보자. 먼저 고객이 고객 ID를 입력해 프로필을 검색할 수 있는 웹 애플리케이션을 개발했다고 치자. 웹 애플리케이션 프런트 엔드는 사용자가 입력한 고객 ID를 백엔드 데이터베이스로 전달한다. 데이터베이스는 SQL 쿼리를 실행하고 웹 애플리케이션에 결과를 반환해 결과가 최종 사용자에 표시된다. 이때 백엔드 데이터베이스 쿼리는 아마 다음과 같은 형태일 것이다.

SELECT *
FROM customers
WHERE customer_id = '1234567'


이때 사용자가 웹 서식 입력란에 다음의 고객 id를 입력했다고 가정해 보자.

1234567; DELETE * customers WHERE '1' = '1

그러면 백엔드 데이터베이스는 다음 SQL을 실행한다.

SELECT *
FROM customers
WHERE customer_id = '1234567';
DELETE *
FROM customers
WHERE 'x' = 'x'


데이터베이스는 여러 개의 SQL 스테이트먼트(Statement)를 세미콜론으로 분리한 경우 반색을 하고 실행하는 속성이 있다. 따라서 사용자가 인용 "" 문자로 입력한 것을 제대로 걸러내지 못하면 해커가 데이터 전체를 삭제할 수 있다. 일단 공격을 받으면 남은 것은 기도밖에 없다. 백업을 제대로 해 놓았기를 기도하고 기도하자.

이번 사례는 의도적으로 간소화했지만 다양한 SQL 인젝션 공격의 작동원리는 기본적으로 같다. 웹 애플리케이션이 입력부에서 적당히 걸러내지 못하면 원격 SQL 코드 실행으로 이어질 수 있다.

SQL 인젝션 탐지하기
SQL 인젝션 공격을 완화하는 것은 어렵지 않다. 그러나 아무리 똑똑하고 선의를 가진 개발자라도 실수를 하기 마련이다. 따라서 공격 위험을 탐지하는 것은 SQL 인젝션 공격의 위험을 낮추는 매우 중요한 요소다. 대표적인 것이 WAF(Web Application Firewall)다. WAF를 이용하면 기본적인 SQL 인젝션 공격을 탐지해 차단할 수 있다. 그러나 이것에만 의존해서는 곤란하다.

WAF 외에 IDS(Intrusion Detection System)도 네트워크 및 호스트(Host) 기반으로 SQL 인젝션 공격을 탐지한다. 네트워크 기반 IDS는 데이터베이스 서버에 대한 모든 연결을 모니터링하고 의심스러운 활동을 잡아낸다. 호스트 기반 IDS는 웹 서버 로그를 모니터링하고 악의적인 일이 발생할 가능성이 있으면 경고를 보낸다. 궁극적으로 SQL 인젝션 공격은 쉽게 파악해 예방할 수 있다. 따라서 위험 완화의 우선순위는 처음부터 SQL 인젝션 공격을 예방하는 것이어야 한다.

SQL 인젝션을 예방하는 방법
SQL 인젝션 공격을 막으려면 데이터베이스 입력에서 부적당한 부분을 제거하면 된다. 웹 애플리케이션 데이터베이스에 대한 입력은 일단 신뢰할 수 없다고 간주하고 이에 따라 처리해야 한다. OWASP 관계자는 "코드에서 SQL 인젝션 취약성을 피하기는 매우 쉽다. 그러나 안타깝게도 바로 이 때문에 SQL 인젝션 공격이 성공하는 경우가 많다"라고 말했다.

실무적으로 참고할 만한 자료를 찾는다면 OWASP SQL 인젝션 처리 가이드를 보면 된다. 점점 완성도가 좋아지고 있다. 단, OWASP는 SQL 인젝션 공격을 막으려면 개발자가 입력 검증을 (블랙리스트(Blacklist)가 아니라) 화이트리스트(Whitelist) 처리하고 파라미터화된 쿼리를 이용해 준비된 스테이트먼트를 사용하며 사용자 완전히 자유롭게 입력할 수 있도록 허용해선 안된다고 조언했다.

계정의 권한을 제한하는 것도 중요하다. 개발자도 인간일 뿐이다. 보안 측면에서는 개발자가 악의적인 입력을 다 걸러내지 못한다고 가정해야 한다. 그렇다면 데이터베이스 사용자의 계정 권한을 제한하는 것이 매우 효과적이다. 예를 들어, 웹 애플리케이션은 읽기 전용인가? 드롭 테이블(DROP TABLES) 권한이 필요한가? 아마도 대부분의 경우 그렇지 않을 것이다. 따라서 최소 권한의 원칙을 적용하는 것이 좋다. 웹 애플리케이션에 구동에 필요한 최소한의 권한만 부여해야 한다.

이렇게 한다고해도 완벽하지 않다. SQL 인젝션이 조금 더 어려워졌지만 불가능한 것은 아니다. 웹 애플리케이션이 몇가지 SQL 쿼리만 실행한다면 이런 쿼리를 실행하기 위해 보통 스토어드 프로시저(Stored procedures)를 생성한다. 이는 일반적으로 데이터베이스 관리자만 생성 또는 수정할 수 있다. 하지만 많은 데이터베이스가 기본 스토어드 프로시저를 제공하며, 해커 역시 이 사실을 잘 알고 있다. 따라서 정말 필요하지 않다면 스토어드 프로시저를 삭제하는 것이 좋다.

웹 보안의 시작
사실 SQL 인젝션은 가장 쉬운 웹 애플리케이션 보안이다. 초보 해커도 손쉽게 시도할 수 있지만 개발자가 약간만 신경쓰면 손쉽게 대비할 수 있다. 벌써 2018년이다. 더 이상 SQL 인젝션에 취약한 웹 애플리케이션을 변경할 수 있는 근거는 아무 데도 없다. SQL 인젝션은 문자 그대로 최소한의 웹 애플리케이션 보안이다. ciokr@idg.co.kr 

2018.02.28

'웹 보안의 시작과 끝' SQL 인젝션의 정의와 대응방법

J.M. Porup | CSO
SQL 인젝션(SQL injection, SQLi)은 웹 애플리케이션 데이터베이스를 완전히 통제할 수 있는, 비교적 단순한 웹 애플리케이션 보안 공격이다. 1998년에 처음 발견된 이후 현재까지 인터넷에서 웹 애플리케이션을 괴롭히고 있다. 심지어 OWASP(The Open Web Application Security Project)의 보안 위협 순위 톱 10을 보면, SQL 인젝션이 웹 애플리케이션 최악의 위협으로 올라와 있다.



다행인 것은 SQL 인젝션이 공격자와 방어자 모두에게 매우 쉽다(?)는 것이다. 너무 쉬워서 첨단 NSA 쉐도우 브로커(Shadow Broker) 키트도 필요없다. 3살짜리도 할 수 있다. 동시에 이 어린애 장난 같은 스크립트와 위험을 완화하기 위해 웹 애플리케이션을 고치기도 너무 쉽다. 오히려 이를 수정하지 않는 것이 중대한 과실로 비치고 있다.

SQL 인젝션의 정의와 유형
SQL 인젝션의 유형은 여러 가지지만 핵심은 하나다. 공격자가 임의의 SQL을 웹 애플리케이션 데이터베이스 쿼리(Query)에 삽입하는 것이다.

가장 간단한 형태의 SQL 인젝션은 사용자 입력을 통한 것이다. 웹 애플리케이션은 일반적으로 서식을 통해 사용자 입력을 받아들인다. 이후 프런트 엔드(Front End)가 처리를 위해 백엔드(Back-end) 데이터베이스로 전달한다. 이 과정에서 웹 애플리케이션이 사용자 입력의 문제가 되는 곳을 걸러내지 못하면 해커가 원하는 SQL을 백엔드 데이터베이스에 입력해 데이터베이스의 내용을 삭제, 복사 또는 수정할 수 있다.

또한 공격자는 쿠키(Cookies)를 수정해 웹 애플리케이션의 데이터베이스 쿼리에 악영향을 끼칠 수 있다. 쿠키는 고객 상태 정보를 로컬에 저장하는데, 웹 애플리케이션은 일반적으로 쿠키를 불러와 해당 정보를 처리한다. 악의적인 사용자 또는 악성코드는 이 쿠키를 수정해 특정 SQL을 백엔드 데이터베이스에 입력할 수 있다.

HTTP 헤더(Header) 등의 서버 변수 또한 SQL 인젝션 공격 벡터로 사용된다. 임의의 SQL이 포함된 위조 헤더를 웹 애플리케이션이 걸러 내지 못하면 이 코드가 그대로 데이터베이스에 입력된다. 2차 SQL 인젝션 공격도 있다. 곧바로 실행되지 않고 나중에 실행되므로 가장 교활하다. 즉각적인 공격을 막기 위해 취약점을 제대로 제거하는 개발자도 2차 SQL 인젝션에 당하는 경우가 종종 있다.

SQL 인젝션 방법은?
SQL 인젝션의 역사는 꽤 길다. 이미 오래 전부터 자동화된 작업이기도 하다. SQL닌자(SQLninja), SQL맵(SQLmap) 및 하비즈(Havij) 등의 툴로 웹 애플리케이션을 손쉽게 테스트할 수 있다. 반면 이는 공격자에게도 마찬가지로 간단하다. 10년 전, 한 SQL 인젝션 웜(Worm)이 인터넷에서 난동을 부린 적이 있다. 그러나 현재도 크게 달라진 것은 없다. SQL 인젝션을 하나의 문제로 널리 인식하고 있지만 많은 웹 애플리케이션이 여전히 취약하다.

그래서 자동화된 테스트 툴이 한 대안이다. 이를 통해 손쉬운 공격 대상을 찾는 해커보다 한발 앞서 대비할 수 있다. SQL맵 등의 툴을 이용해 웹 애플리케이션 침투 테스트를 진행하는 것이 가장 간편하다. SQL맵은 현재 사용하는 거의 모든 주요 데이터베이스를 지원하며 알려진 대부분의 SQL 인젝션 취약성을 감지한다. 이들 툴은 입력 사항을 정리 테스트하고 대비책이 제대로 작동하고 있는지 검증한다.


SQL 인젝션 공격 사례
기본적인 SQL 인젝션 공격을 살펴보자. 먼저 고객이 고객 ID를 입력해 프로필을 검색할 수 있는 웹 애플리케이션을 개발했다고 치자. 웹 애플리케이션 프런트 엔드는 사용자가 입력한 고객 ID를 백엔드 데이터베이스로 전달한다. 데이터베이스는 SQL 쿼리를 실행하고 웹 애플리케이션에 결과를 반환해 결과가 최종 사용자에 표시된다. 이때 백엔드 데이터베이스 쿼리는 아마 다음과 같은 형태일 것이다.

SELECT *
FROM customers
WHERE customer_id = '1234567'


이때 사용자가 웹 서식 입력란에 다음의 고객 id를 입력했다고 가정해 보자.

1234567; DELETE * customers WHERE '1' = '1

그러면 백엔드 데이터베이스는 다음 SQL을 실행한다.

SELECT *
FROM customers
WHERE customer_id = '1234567';
DELETE *
FROM customers
WHERE 'x' = 'x'


데이터베이스는 여러 개의 SQL 스테이트먼트(Statement)를 세미콜론으로 분리한 경우 반색을 하고 실행하는 속성이 있다. 따라서 사용자가 인용 "" 문자로 입력한 것을 제대로 걸러내지 못하면 해커가 데이터 전체를 삭제할 수 있다. 일단 공격을 받으면 남은 것은 기도밖에 없다. 백업을 제대로 해 놓았기를 기도하고 기도하자.

이번 사례는 의도적으로 간소화했지만 다양한 SQL 인젝션 공격의 작동원리는 기본적으로 같다. 웹 애플리케이션이 입력부에서 적당히 걸러내지 못하면 원격 SQL 코드 실행으로 이어질 수 있다.

SQL 인젝션 탐지하기
SQL 인젝션 공격을 완화하는 것은 어렵지 않다. 그러나 아무리 똑똑하고 선의를 가진 개발자라도 실수를 하기 마련이다. 따라서 공격 위험을 탐지하는 것은 SQL 인젝션 공격의 위험을 낮추는 매우 중요한 요소다. 대표적인 것이 WAF(Web Application Firewall)다. WAF를 이용하면 기본적인 SQL 인젝션 공격을 탐지해 차단할 수 있다. 그러나 이것에만 의존해서는 곤란하다.

WAF 외에 IDS(Intrusion Detection System)도 네트워크 및 호스트(Host) 기반으로 SQL 인젝션 공격을 탐지한다. 네트워크 기반 IDS는 데이터베이스 서버에 대한 모든 연결을 모니터링하고 의심스러운 활동을 잡아낸다. 호스트 기반 IDS는 웹 서버 로그를 모니터링하고 악의적인 일이 발생할 가능성이 있으면 경고를 보낸다. 궁극적으로 SQL 인젝션 공격은 쉽게 파악해 예방할 수 있다. 따라서 위험 완화의 우선순위는 처음부터 SQL 인젝션 공격을 예방하는 것이어야 한다.

SQL 인젝션을 예방하는 방법
SQL 인젝션 공격을 막으려면 데이터베이스 입력에서 부적당한 부분을 제거하면 된다. 웹 애플리케이션 데이터베이스에 대한 입력은 일단 신뢰할 수 없다고 간주하고 이에 따라 처리해야 한다. OWASP 관계자는 "코드에서 SQL 인젝션 취약성을 피하기는 매우 쉽다. 그러나 안타깝게도 바로 이 때문에 SQL 인젝션 공격이 성공하는 경우가 많다"라고 말했다.

실무적으로 참고할 만한 자료를 찾는다면 OWASP SQL 인젝션 처리 가이드를 보면 된다. 점점 완성도가 좋아지고 있다. 단, OWASP는 SQL 인젝션 공격을 막으려면 개발자가 입력 검증을 (블랙리스트(Blacklist)가 아니라) 화이트리스트(Whitelist) 처리하고 파라미터화된 쿼리를 이용해 준비된 스테이트먼트를 사용하며 사용자 완전히 자유롭게 입력할 수 있도록 허용해선 안된다고 조언했다.

계정의 권한을 제한하는 것도 중요하다. 개발자도 인간일 뿐이다. 보안 측면에서는 개발자가 악의적인 입력을 다 걸러내지 못한다고 가정해야 한다. 그렇다면 데이터베이스 사용자의 계정 권한을 제한하는 것이 매우 효과적이다. 예를 들어, 웹 애플리케이션은 읽기 전용인가? 드롭 테이블(DROP TABLES) 권한이 필요한가? 아마도 대부분의 경우 그렇지 않을 것이다. 따라서 최소 권한의 원칙을 적용하는 것이 좋다. 웹 애플리케이션에 구동에 필요한 최소한의 권한만 부여해야 한다.

이렇게 한다고해도 완벽하지 않다. SQL 인젝션이 조금 더 어려워졌지만 불가능한 것은 아니다. 웹 애플리케이션이 몇가지 SQL 쿼리만 실행한다면 이런 쿼리를 실행하기 위해 보통 스토어드 프로시저(Stored procedures)를 생성한다. 이는 일반적으로 데이터베이스 관리자만 생성 또는 수정할 수 있다. 하지만 많은 데이터베이스가 기본 스토어드 프로시저를 제공하며, 해커 역시 이 사실을 잘 알고 있다. 따라서 정말 필요하지 않다면 스토어드 프로시저를 삭제하는 것이 좋다.

웹 보안의 시작
사실 SQL 인젝션은 가장 쉬운 웹 애플리케이션 보안이다. 초보 해커도 손쉽게 시도할 수 있지만 개발자가 약간만 신경쓰면 손쉽게 대비할 수 있다. 벌써 2018년이다. 더 이상 SQL 인젝션에 취약한 웹 애플리케이션을 변경할 수 있는 근거는 아무 데도 없다. SQL 인젝션은 문자 그대로 최소한의 웹 애플리케이션 보안이다. ciokr@idg.co.kr 

X