그동안 프로그래머스 문제풀이, 교재를 활용한 DB 이론 학습을 끝내고 단순히 SQL을 작성해 데이터를 가져올 때 보안 상의 문제는 어떻게 해결하는지 알고자 Injection에 대한 학습을 진행하기로 했다.
: 웹 사이트 내 보안 상 허점을 이용해 특정 SQL 쿼리문을 전송해 공격자가 원하는 DB의 중요 정보를 가져오는 해킹 기법을 의미한다.
- 1) Error based SQL Injection - 논리적 취약점을 이용한 SQL 인젝션
SELECT * FROM CLIENT WHERE id = 'input1' and password = 'input2' SELECT * FROM CLIENT WHERE id ='' OR 1 = 1--
위 예시를 살펴보면, OR 1=1--로 WHERE절을 모두 참으로 만들고 --를 사용해 뒷부분을 주석처리하여 CLIENT 테이블 내 모든 데이터를 조회할 수 있게 되고 관리자 계정에 접근할 수 있게 된다.
- 2) UNION based SQL Injection : UNION 명령어를 이용한 SQL 인젝션
: SQL에서 UNION 키워드는 두 개의 쿼리문에 대해 결과를 통합해 하나의 테이블을 보여주게 하는 키워드, UNION 시 두 테이블의 컬럼 수와 데이터 타입이 동일해야 한다.SELECT * FROM BOARD WHERE title LIKE % 'UNION SELECT null, id, password FROM CLIENT --
위 예시를 살펴보면, 입력값을 테이블 내 컬럼 값들과 비교한 뒤 비슷한 글자가 있는 데이터를 출력하게 된다. >> 입력값에 대한 검증이 필요한 부분을 보여주는 문제
- 3) Blind SQL Injection : Boolean based SQL Injection
: 데이터베이스로 부터 특정 값을 전달받지 않고 단순히 TRUE/FALSE의 정보만 알 수 있을 때 사용된다.SELECT * FROM CLIENT WHERE id = 'abc123' and ASCII(SUBSTR(SELECT NAME FROM INFROMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'based table' limit 0,1) 1, 1)) > 100 --
위 예시는 Blind Injection을 이용해 테이블 명을 조회하는 방법의 예시. 이처럼 테이블 명을 알아낸 후 2차 피해를 가하는 방법이 존재한다.
- 4) Blind SQL Injection : Time based SQL Injection
SELECT * FROM CLIENT WHERE id = 'abc123' OR (LENGTH(DATABASE()) = 1 AND SLEEP(2))
SLEEP() 혹은 BENCHMARK() 함수를 사용해 현재 사용 중인 DB의 길이를 알아내는 방법
5) Stored Procedure SQL Injection
: stored procedure는 일련의 쿼리를 모라 하나의 함수처럼 사용하기 위한 것으로 공격에 사용되는 대표 프로시저는 MS-SQL에 있는 xp_cmdshell로 윈도우 명령어를 사용할 수 있게 된다.6) Mass SQL Injection
한 번의 공격으로 다량의 DB가 큰 피해를 입는 것으로, MS-SQL을 사용하는 ASP기반 웹 어플리케이션에서 많이 발생하며 쿼리문은 HEX인코딩 방식으로 인코딩해 공격을 하는 인젝션
1) 입력 값에 대한 검증
: 서버 단에서 화이트리스트를 기반으로 검증에 시도해야 한다.
- Error message 노출 금지
2) 웹 서버 내에서의 조치
- 웹 서버의 오류정보가 사용자에게 노출되지 않도록 조치
- 웹 어플리케이션과 연동되는 DB 접근 최소화
- 사용자 입력 폼을 대상으로 특수문자, 구분 등의 필터링 규칙 적용
3) Filtering 규칙 적용
- mysqli_real_escape_string : 인자로 들어온 string에서 공격 관련 기호를 문자로 변환
- preg_match : 사용자의 input값에 특정 문자열을 사용 못하도록 막는 함수
4) Prepared Statement 구문 사용
- SQL 구문을 먼저 컴파일한 이후 사용자의 입력값을 바인딩하는 방식, 사용자가 입력한 값이 SQL문이 아닌 문자열로 인식되도록 함.
- 대부분 SQL 주입 인스턴스는 문자열 연결 대신 매개변수화 된 쿼리(Prepared statement) 사용해 방지 가능
PreparedStatement statement = connection.prepareStatement("SELECT * FROM products WHERE category = ?"); statement.setString(1, input); ResultSet resultSet = statement.executeQuery();
매개변수화 된 쿼리 WHERE 절은 삽입, 갱신 문의 절과 값을 포함해 신뢰할 수 없는 입력이 쿼리 내 데이터로 나타난 모든 상황에 사용 가능하다.