관리 메뉴

nalaolla

SQL Injection과 DB 보안 본문

MS-SQL

SQL Injection과 DB 보안

날아올라↗↗ 2015. 12. 20. 15:48
728x90

웹사이트를 제작하면서 SQL Injection 이라는 것에 대해서 한번쯤은 들어 보았을 것이다. 아직 SQL Injection 에 대한 자료가 부족한 분들을 위해, SQL Injection의 원리와 대응책, 그리고 효율적인 DB 보안에 대해 알아보고자 한다.

SQL Injection 이 대체 무엇이길래, 보안컨설팅에서 그토록 자주 논하는 것일까? 쉽게 설명하면, 개발자가 작성한 SQL구문을 침투하여, 의도하지 않은 결과가 일어나도록 하는 것이다. 개발자들은 자신의 웹 어플리케이션이 웹을 통한 접근이나 기타 해킹 툴을 통해서 얼마든지 가능하다는 것을 인식해야 한다는 것을 말한다. 이는 단순히 정보를 빼나가는 것이 아니라, 데이터를 초기화 할 수도 있음을 말한다.

아래와 같은 쿼리가 존재한다고 가정해보자. (가독성을 높이기 위해 테이블, 칼럼 명을 한글로 기재한다.)

SELECT * FROM [공지사항] WHERE [제목] = '검색어'


단순히 [공지사항]이라는 테이블에서 [제목] 필드를 조회하여 정보를 가져오는 쿼리이다. '검색어'는 GET 이나 POST 방식으로 전달될 것이다. 이 검색어를 다음과 같이 보내게 된다면 어떻게 될까?

SELECT * FROM [공지사항] WHERE [제목] = '검색어';DROP TABLE [공지사항]'


SELECT 후에 깔끔하게 [공지사항] 테이블을 없앨 것이다. 

이해가 되지 않는 다면 다음 쿼리를 살펴보자.

SELECT * FROM [회원] WHERE [아이디] = '입력값' AND [비밀번호] = '입력값'


이 쿼리는 아이디와 비밀번호 비교를 통해 로그인하는 쿼리이다. 아이디 입력값을 아래와 같이 보내보자.

SELECT * FROM [회원] WHERE [아이디] = 'TEST'--' AND [비밀번호] = '입력값'


이 쿼리가 실행이 되면 TEST 후에 구문은 주석으로 인식이 되게 되며 비밀번호 체크 없이 TEST 계정이 존재한다면 정상적으로 로그인이 될 것이다.
어려운 쿼리가 아니므로 Injection 원리에 대해 쉽게 이해가 될 것이다.

그렇다면, SQL Injection 을 막는 기법은 무엇일까? 많은 분들이 Stored Procedure로 쿼리를 작성하면 된다고 알고 있다. 하지만, 이는 100% 해결 방안이 아니다. 예를 들어보자.

공지사항을 가져오는 쿼리를 Stored Procedure 로 작성한다.
CREATE Procedure dbo.[공지사항가져오기]
@검색어 VARHCAR(10)
AS
SET NOCOUNT ON
SELECT * FROM [공지사항] WHERE [제목] = @검색어
SET NOCOUNT OFF

** ASP 페이지
1. 의도된 사용.
Dim objRs, strSql
Set objRs = Server.CreateObject("ADODB.RECORDSET")
strSql = "exec [공지사항가져오기] '"& 검색어 &"'"
objRs.Open strSql, [연결문자열] -- 생략..

2. Injection 침투
strSql = "exec [공지사항가져오기] '"& 검색어';DROP TABLE [공지사항] --&"'"
objRs.Open strSql, [연결문자열] -- 생략..


검색어에 "검색어';DROP TABLE [공지사항] --" 값을 전달한다면, 레코드셋 객체는 친절하게 DROP 구문을 실행시켜줄 것이다. 이 쿼리가 회원테이블과 같이 공격에 의해 치명적인 타격을 입는 테이블이라고 가정해 보라. 따라서, Stored Procedure의 사용은 SQL Injection을 막는 방법이 아니다는 것을 명심해야 한다.

위에서 설명한 것은 SQL Injection의 가장 보편적인 예일 뿐이다. 하지만, 이런 방식만으로도 쉽게 뚫리는 웹사이트가 많은 것을 볼 때 침입자를 탓할 수도 없으며, 개발환경을 탓할 수도 개발자를 탓할 수도 없는 상황이 된다.

개발자들에 의해 SQL Injection 을 막는 방법으로, Stored Procedure 사용, Single Quotation 치환, Command 객체 사용 등 여러 방법들이 동원되고 있지만, 필자는 그러한 방법들을 100% 신뢰하지 않는다. 이러한 방법은 궁극적인 해결책이 될 수 없으며, 또한 필자가 해커가 아닌 이상, 해커들의 수많은 침투방법을 모두 예상하지 못하기 때문이다. 

그렇다면, 어떠한 방법을 통해 DB에 대한 보안성을 강화할 수 있을까? 

1. Stored Procedure로 100% 작성하라. 이는 보안과 성능 향상에 큰 효과를 준다.
2. Stored Procedure에 전달되는 모든 Parameter의 무결성을 체크하라. (Size 체크, 비허용문자열 치환등)
- Table Column Size에 맞는 파라미터를 전송하며, SQL Injection이 의심되는 문자열은 모두 치환한다.
3. DB 서버 연결계정 보관소를 웹소스와 분리한다. (2005-04-18일자 칼럼 참조)
4. DB 서버와 WEB 서버를 분리한 후 DB 서버의 공인 IP를 제거하라. 그리고, WEB 서버와의 통신에 필요한 포트를 제외한 모든 포트를 막는다.
5. 웹에서 사용하는 DB 서버 연결계정의 권한을 축소한다.
- SA 계정을 절대 사용해서는 안된다. (SA 계정 권한 획득을 통해 DB에 대한 모든 작업을 수행할 수 있다.)
- 사용자 계정(연결계정)을 DB_Owner로 생성하지 않는다. (DB_Owner는 자신이 소유한 DataBase에 한해 모든 작업을 수행할 수 있다.)
- 사용자 계정은 Public 권한만 부여한 후, 작성된 Stored Procedure에 EXECUTE 권한을 부여한다. 이렇게 되면, 웹을 통한 DB 계정을 빼내어 권한을 획득한다 하더라도, 해당 테이블에 권한이 없기 때문에 의도되지 않은 실행을 제어할 수 있게 된다.

Public 에 속한 계정이라 할 지라도, sysobjects와 syscolumns에 대해 SELECT 권한이 기본적으로 부여가 되어 있기 때문에, 해킹을 통해 각 테이블 정보를 빼나가기란 쉽다. 하지만, 그 계정이 테이블에 대한 DML문에 대한 권한이 존재 하지 않는다면, 개발자가 권한을 부여한 Stored Procedure를 제외한 다른 처리를 취할 수 없으므로, 이를 통해 보안이 강화되게 된다는 것을 기억하기 바라며 DB 연결계정의 권한 축소를 꼭 실행하기 바란다.

예전에 모방송국 프로그램에서 해커가 이런 얘기를 한 것을 본적이 있다. "전화선 하나만 있으면 모든 시스템을 뚫을 수 있다" 이 얘기가 과장일지 아닐지는 모르지만, 보안을 염두에 두고 만든 어플리케이션은 그만큼 안정성이 부여되므로 늘 보안에 대해 고민하길 바라며 이 글을 마친다.



728x90