티스토리 뷰

Study/CS

[데이터베이스] SQL Injection

나갱 2022. 7. 9. 14:35

SQL Injection(SQL 삽입 공격)

SQL Injection(SQL 삽입 또는 SQL 주입)은 악의적인 사용자가 보안상의 취약점을 이용하여 클라이언트의 입력 값을 조작하여 서버의 데이터베이스를 공격할 수 있는 공격방식을 말한다. 이러한 Injection 계열의 취약점들은 테스트를 통해 발견하기는 힘들지만 스캐닝툴이나 코드 검증절차를 거치면 보통 쉽게 발견되기 때문에 탐지하기에는 쉬운편이다. 보안회사 Imperva 가 2012년에 발표한 내용을 따르면 월 평균 4회가량의 SQL Injection 공격이 일어난다고 한다. OWASP 에서도 수년 동안 Injection 기법이 보안 위협 1순위로 분류되었던 만큼 각별한 주의가 필요하다. 

 


공격 방법

 

방법 1. 인증 우회 

 

보통 아이디와 패스워드를 입력하는 로그인 페이지를 타겟으로 행해지는 공격이다. SQL 쿼리 문의 True/False의 논리적인 연산 오류를 이용하여 로그인 인증 쿼리문이 무조건 True의 결과 값이 나오게 하여 인증을 무력화 시키는 원리이다.

 

 

'OR 1=1 --' 을 삽입하여 WHERE 절에 있는 싱글 쿼터를 닫아주기 위한 싱클 쿼터와 OR 1=1 라는 구문을 이용하여 WHERE절을 모두 참으로 만들고, -- 를 넣어줌으로 뒤의 구문을 모두 주석 처리 해주었다. 

 

매우 간단한 구문이지만, 결론적으로 Users 테이블에 있는 모든 정보를 조회하게 됨으로써 가장 먼저 만들어진 계정으로 로그인에 성공하게 된다.

 

로그인 뿐만 아니라 JOIN이나 UNION 같은 구문을 통해 공격자가 원하는 코드를 실행할 수도 있다. 

 

SQL에서 Union 키워드는 두 개의 쿼리문에 대한 결과를 통합해서 하나의 테이블로 보여주게 하는 키워드이다. 정상적인 쿼리문에 Union 키워드를 사용하여 인젝션에 성공하면 원하는 쿼리문을 실행할 수 있게 된다. Union Injection 을 성공하기 위해서는 Union 하는 두 테이블의 컬럼 수와 데이터 형이 같아야 한다.

 

 

 

위의 사진에서 보이는 쿼리문은 Board 라는 테이블에서 게시글을 검색하는 쿼리문이다. 입력 값을 title과 contents 컬럼의 데이터랑 비교한 뒤 비슷한 글자가 있는 게시글을 출력한다. 현재 인젝션 한 구문은 사용자 id와 password를 요청하는 쿼리문이다. 인젝션에 성공하게 되면 사용자의 개인 정보가 게시글과 함께 화면에 보여지게 된다. 

 

 

방법 2.  데이터 노출

 

시스템 에러는 개발자에게 버그를 수정하는 면에서 많은 도움을 주지만 역으로 에러를 이용할 수도 있다. 악의적인 구문을 삽입하여 에러를 유발시키는 것이다. 해커는 GET 방식으로 동작하는 URL 에 추가적인 'Query String'을 추가하여 에러를 발생시킬 수 있다. 이에 해당하는 오류가 나타난다면 그것을 가지고 데이터베이스의 구조를 유추할 수 있다. 때문에 오류 페이지 또는 오류 메세지가 노출되어서는 안된다. 

 


대응 방안

 

방법 1. 입력 값에 대한 검증

 

사용자의 입력이 DB Query 에 동적으로 영향을 주는 경우, 입력된 값이 개발자가 의도한 값인지 검증한다.

즉, 로그인 전 검증 로직을 추가하여 미리 설정한 특수문자(아래 예시)들이 들어왔을 때 요청을 막아낸다.

의도하지 않은 입력 값에 대해 검증하고 차단하게 된다. 

 

/*, –, ‘, “, ?, #, (, ), ;, @, =, *, +, union, select, drop, update, from, where, join, substr, user_tables, user_table_columns, information_schema, sysobject, table_schema, declare, dual,…

 

 

방법 2. 저장 프로시저 사용

 

저장 프로시저는 사용하고자 하는 Query 에 미리 형식을 지정하는 것을 말한다. 지정된 형식의 데이터가 아니면 Query 가 실행되지 않기 때문에 보안성을 크게 향상 시킬 수 있다.  

 

방법 3. SQL 서버 오류 발생 시, 해당하는 Error Message 노출 금지

 

공격자가 SQL Injection 을 수행하기 위해서는 데이터베이스의 정보가 필요하다. 데이터베이스 에러 발생 시 따로 처리를 해주지 않는다면 에러가 발생한 쿼리문과 함께 에러에 관한 내용을 반환해주게 된다. 여기서 테이블 명 및 컬럼 명 그리고 쿼리문이 노출될 수 있기 때문에 데이터베이스에 대한 오류 발생 시 사용자에게 보여줄 수 있는 페이지 제작 또는 메시지 박스를 띄우도록 해야 한다.

 

View 를 활용하면 테이블의 일부만 보일 수 있고 접근 권한을 다르게 할 수도 있다. 원본 테이블에는 접근 권한을 높이고 일반 사용자는 View로 만 접근하게 되면 원본 테이블이 공격에 의해 노출되는 정도를 줄일 수 있다. 

 

 

방법 4. prepared statement 구문 사용

 

일반적으로 SQL 쿼리의 실행 과정은 '구문 분석(Parsing) → SQL 최적화(Optimization)  → 실행 계획을 실행 가능한 코드로 포맷팅 (Row Source Generation)  → 실행(Execute)  → 인출(Fetch)' 총 다섯가지 단계로 구성되어 있다고 축약할 수 있다. 매번 동적으로 쿼리를 생성하는 일반적인 Statement 를 사용하게 되면 구문 분석부터 인출까지의 모든 과정을 수행하게 된다.

 

Prepared Statement 란 미리 쿼리에 대한 컴파일을 수행하고, 입력 값을 나중에 넣는 방식이다. 즉, 일반적인 Statement 와 다르게 불필요하게 모든 과정을 수행하지 않고 실행(Execute) 전까지의 과정을 최초로 한 번만 수행한 후 나중에는 실행 전에 미리 컴파일 되어있는  Prepared Statement 를 가져다 쓰는 것이다.

 

Prepared Statement 는 자주 수행되는 복잡한 쿼리들의 성능을 개선하기 위해 많이들 사용하지만, SQL Injection 에 대한 대응 방법으로서 역할을 하기도 한다. Prepared Statement 를 활용하면 쿼리의 문법 처리 과정이 미리 컴파일이 되어있기 때문에, 외부 입력 값으로 SQL 관련 구문이나 특수 문자가 들어와도 그것은 SQL 문법으로서 역할을 할 수 없기 때문이다.

 

자바의 JDBC 코드를 예로 들자면 서비스에 로그인하는 쿼리를 Prepared Statement 로 작성하면 다음과 같다.

 

PreparedStatement stmt = conn.prepareStatement("SELECT * FROM USER WHERE ID =? AND PASSWORD =?")

 

위 코드에서 실제 쿼리 변수가 들어갈 자리는 ?로 작성되어 있어서 특정 값은 지정하지 않은 채로 남겨지게 되는데, 변수 stmt 가 생성되는 순간 연결되어 있는 DBMS 에서는 위 쿼리에 대해 컴파일을 수행해 놓는다. 컴파일 된 결과는 템플릿과 같이 사용되며, 나중에 저 쿼리가 실제로 수행되어야 하는 순간 넘겨 받은 입력 값을 ?에 바인딩 시켜주고 쿼리가 실행되게 된다.

 

 

'Study > CS' 카테고리의 다른 글

[운영체제] PCB 와 Context Switching  (0) 2022.07.17
[데이터베이스] 인덱스(Index)  (0) 2022.07.17
[컴퓨터구조] ARM 프로세서(ARM Processor)  (0) 2022.07.09
[네트워크] TLS/SSL handshake  (0) 2022.07.03
[네트워크] HTTP & HTTPS  (0) 2022.07.02
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함