SQL Injection (SQL 삽입 공격)
- 악의적인 사용자가 보안상의 취약점을 이용하여 임의의 SQL 문을 주입하고 실행되게 하여 데이터베이스가 비정상적인 동작을 하도록 조작하는 행위
- SQL Injection 공격은 OWASP Top 10 중 첫번쨰에 속해 있으며, 공격이 비교적 쉬운 편이고 공격에 성공할 경우 큰 피해를 입힐 수 있다
- 이는 대부분 클라이언트가 입력한 데이터를 제대로 필터링하지 못하는 경우에 발생한다
SQL Injection의 성립 조건
- 웹 애플리케이션이 DB와 연동되어 있다
- 사용자가 입력한 외부 입력값이 SQL 구문의 일부로 사용된다
위의 두 조건을 만족해야 SQL Injection이 가능하다
그러나 현대 웹 애플리케이션의 대부분은 위 조건들을 충족하고 있기 때문에 SQL Injection의 대상이 될 수 있다
SQL Injection의 발생 원인
- 데이터베이스와 연동된 웹 애플리케이션에서 입력된 데이터에 대한 유효성 검증을 하지 않아 발생하는 취약점이다
- 취약한 앱 애플리케이션은 사용자로부터 입력된 값을 필터링 과정 없이 넘겨받아 동적 쿼리(Dynamic Query)를 생성한다
- 이로인해 개발자가 의도하지 않은 쿼리가 생성되어 정보 유출에 악용될 수 있는 것이다
SQL Injection의 공격 방법
1. 인증 우회
보통 로그인을 할 떄, 아이디어와 비밀번호를 input 창에 입력하게 된다
예를 들어 아이디가 abc, 비밀번호가 1234인 경우, 쿼리는 다음과 같은 방식으로 전송된다
SELECT * FROM USER WHERE ID = "abc" AND PASSWORD = "1234";
SQL Injection은 공격할 때 input 창에 비밀번호를 입력함과 동시에 다른 쿼리문을 입력하는 것이다
1234; DELETE * USER FROM ID = "1";
보안이 완벽하지 않은 경우, 이처럼 비밀번호가 아이디와 일치해서 True가 되고 뒤에 작성한 DELETE 문도 데이터베이스에 영향을 줄 수도 있게 되는 치명적인 상황이다
이 밖에도 기본 쿼리문의 WHERE 절에 OR 문을 추가하여 '1'='1' 과 같은 true 문을 작성하여 무조건 적용되도록 수정한 뒤 DB를 마음대로 조작할 수도 있다
2. 데이터 노출
- 시스템에서 발생하는 에러 메시지를 이용해 공격하는 방법이다
- 보통 에러는 개발자가 버그를 수정하는 면에서 도움을 받을 수 있는 존재다
- 해커들은 이를 역이용하여 악의적인 구문을 삽입하여 에러를 유발시킨다
- 예를 들어, 해커는 GET 방식으로 동작하는 URL 쿼리 스트링을 추가하여 에러를 발생시킨다
- 이에 해당하는 오류가 발생하면, 이를 통해 해당 웹앱의 데이터베이스 구조를 유추할 수 있고 해킹에 활용된다
😈 SQL Injection 종류
1. Error based SQL Injection
- 논리적 오류 기반 SQL Injection
- 고의로 SQL 문에 에러를 발생시키는 기법
- 위의 사진처럼 1=1 과 같이 항상 참이 되는 구문을 주입하고 뒤의 조건은 -- 로 주석처리 한다
- 그러면 조건절이 성립되어 Users 테이블의 모든 정보를 조회가 가능하게 된다
- 에러 메시지를 통해 쿼리문의 구성을 추측할 수 있다
- 또한 DB의 테이블명, 컬럼명, 데이터 내용까지도 알아낼 수 있다
2. Blind SQL Injection
- 이는 에러 메시지가 발생하지 않는 경우 주로 사용하는 기법이다
- Blind -> 보이지 않는, 가려진 이라는 의미로 특정 쿼리문으로 인한 결과가 참/거짓인 것만 알 수 있을 때 사용한다
- 예를 들어 로그인 시 성공하면 참, 실패하면 거짓인 것처럼 결과를 알 수 있을 때 사용한다
- 위의 인젝션 쿼리 문은 테이블 명을 조회하는 구문이다
- 해당구문은 MySQL 에서 테이블 명을 조회하는 구문으로 limit 키워드를 통해 하나의 테이블만 조회하고, SUBSTR 함수로 첫 글자만, 그리고 마지막으로 ASCII 를 통해서 ascii 값으로 변환해준다
- 만약에 조회되는 테이블 명이 Users 라면 ‘U’ 자가 ascii 값으로 조회가 될 것이고, 뒤의 100 이라는 숫자 값과 비교를 하게 된다
- 거짓이면 로그인 실패가 될 것이고, 참이 될 때까지 뒤의 100이라는 숫자를 변경해 가면서 비교를 하면 된다
- 공격자는 이 프로세스를 자동화 스크립트를 통하여 단기간 내에 테이블 명을 알아 낼 수 있다
3. Union SQL Injection
- 이는 UNION 쿼리를 사용한 공격 기법을 아우른다
- 공격하는 쿼리와 다른 쿼리를 결합하여 정보를 알아낼 때 사용하는 기법이다
- 위의 그림과 같이 게시글을 조회하는 쿼리에 UNION을 통해서 인젝션한 구문을 넣게 되면 사용자의 개인정보와 게시글이 함께 조회가 된다
- 공격에 성공하기 위해서는 쿼리 두 개의 컬럼 수와 데이터 형이 같아야 한다는 조건이 있다
- UNION 쿼리에 따라 중복 결과를 얻을 수도 있고, 중복 결과를 제거하고 결과를 확인할 수 있다
4. Stored Procedure based SQL Injection
- 저장된 프로시저에서의 SQL Injection
- Stored Procedure는 일련의 쿼리를 하나의 함수처럼 실행하기 위한 쿼리의 집합
- SQL Injection의 취약점으로 인해 웹에서 Stored Procedure에 대한 접근 권한을 가져서 실행이 가능하다
- 시스템 권한을 획득해야 하므로 공격 난이도가 높으나 성공한다면 서버에 직접적인 피해를 입힐 수 있다
5. Mass SQL Injection
- 다량의 SQL Injection
- 기존 SQL Injection과 달리 한번의 공격으로 다량의 데이터베이스가 조작되어 큰 피해를 입히는 것
- 보통 MS-SQL을 사용하는 ASP 기반 웹 애플리케이션에서 많이 사용되며, 쿼리문은 HEX 인코딩 방식으로 인코딩하여 공격한다
- 보통 데이터베이스 값을 변조하여 데이터베이스에 악성 스크립트를 삽입하고, 사용자들이 변조된 사이트에 접속 시 좀비 PC로 감염되게 한다
- 이렇게 감염된 좀비 PC들은 DDos 공격에 사용된다
🥊 SQL Injection 공격 방어
1. 입력값 검증
사용자의 입력이 DB Query에 동적으로 영향을 주는 경우, 입력된 값이 개발자가 의도한 값(유효값)인지 검증한다
/*, –, ‘, “, ?, #, (, ), ;, @, =, *, +, union, select, drop, update, from, where, join, substr, user_tables, user_table_columns, information_schema, sysobject, table_schema, declare, dual,…
입력값을 받을 때 위와 같이 특수문자를 검사하여 의도하지 않은 입력값에 대해 검증하고 차단해야 한다
*Java 입력값 검증 예시 코드
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/* 특수문자 공백 처리 */
final Pattern SpecialChars = Pattern.compile(“[‘\”\\-#()@;=*/+]”);
UserInput = SpecialChars.matcher(UserInput).replaceAll(“”);
final String regex = “(union|select|from|where)”;
final Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
final Matcher matcher = pattern.matcher(UserInput);
if(matcher.find()){
out.println(“<script>alert(‘No SQL-Injection’);</script>”);
}
🖤 블랙 리스트 방식
- SQL 쿼리의 구조를 변경시키는 문자나 키워드, 특수문자를 제한하는 방식이다
- SQL의 예약어인 UNION, GROUP BY와 COUNT() 등의 함수명, 세미콜론(;)이나 주석(--) 등의 특수 문자들을 블랙리스트로 미리 정의하고, 블랙리스트로 지정되어 있는 문자나 키워드가 외부 입력값 안에 존재하면 공백 등으로 치환하는 방식으로 방어한다
- 하지만 정교하게 입력값을 검증하지 않는다면 블랙 리스트 방식의 검증을 우회할 수 있기 때문에 주의해야 한다
- 예를 들어 외부 입력갑셍 SESELECTLECT라는 표현이 있을 때 중간의 SELECT가 공백으로 치환되면, 그 좌우에 있는 문자들이 합쳐져서 다시 SELECT 키워드가 완성된다
🤍 화이트 리스트 방식
- 허용된 문자를 제외하고는 모두 허용되지 않는 방식으로, 금지된 문자 외에는 모두 허용하는 블랙리스트 방식보다 보안성 측면에서는 훨씬 더 강력한 방법이다
- 웹 애플리케이션의 기능에 따라 알맞게 화이트 리스트를 작성해야 하는 번거로움이 존재한다
- 그러한 번거로움을 해결하고 유지보수의 편리함을 증진시키기 위해 개별 문자를 일일이 하나씩 모두 정의하는 것보다 정규식 등을 이용해서 화이트 리스트를 범주화/패턴화시키는 편이 좋다
2. 저장 프로시저 (Prepared Statement) 사용
저장 프로시저는 사용하고자 하는 Query에 미리 형식을 지정하는 것을 말한다
지정한 형식의 데이터가 아니면 Query가 실행되지 않기 때문에 보안성을 크게 향상시킨다
*Java 취약 코드 예시
try{
String uId = props.getProperty(“jdbc.uId”);
String query = “SELECT * FROM tb_user WHERE uId=” + uId;
stmt = conn.prepareStatement(query);
ResultSet rs = stmt.executeQuery();
while(rs.next()){
.. …
}
}catch(SQLException se){
.. …
}finally{
.. …
}
*Java 안전한 코드 예시
try {
String uId = props.getProperty(“jdbc.uId”);
String query = “SELECT * FROM tb_user WHERE uId= ?”
stmt = conn.prepareStatement(query);
stmt.setString(1, uId);
ResultSet rs = stmt.executeQuery();
while(rs.next()){
.. …
}
} catch(SQLException se){
.. …
} finally{
.. …
}
3. 서버 보안
- 최소 권한 유저로 DB를 운영한다
- 사용하지 않는 저장 프로시저와 내장 함수 제거 또는 권한 제어
- 목적에 따라 Query 권한 수정
- 공용 시스템 객체의 접근 제어
- 신뢰할 수 있는 네트워크, 서버에 대해서만 접근 허용
- 에러 메세지 노출 차단
참고)
https://gyoogle.dev/blog/computer-science/data-base/SQL%20Injection.html
https://mong9data.tistory.com/133
https://kk-7790.tistory.com/74
'야미스터디 > Database' 카테고리의 다른 글
[DB] Redis 📌 (0) | 2022.09.13 |
---|---|
[DB] DB View 📌 (0) | 2022.09.07 |
[DB] DDL, DML, DCL 📌 (0) | 2022.08.10 |
[DB] RDB vs NoSQL 📌 (0) | 2022.08.04 |
[DB] DB Index 📌 (0) | 2022.07.17 |
댓글