SQL injection 이란 보안상의 허점을 이용해 사용자가 정의한 SQL 문외 조작된 SQL 을 주입하고 실행시켜 데이터베이스에 저장된 중요한 정보를 가져오는 공격 기법을 의미한다.
Error Based SQL injection
논리적 에러를 이용한 SQL injection
- 잘못된 SQL 을 이용해 고의로 에러를 발생시는 공격 기법이다.
- 예외로 던저진 Message 를 통해 테이블 명과 컬럼과 같은 테이블 정보 를 얻어낼 수 있다.
- SQL 구문 정보를 변경해 사용자 인증을 우회해 접속할 수 있다.
Union Based SQL injection
Union 명령을 이용한 SQL injection
- 정상적으로 실행하는 쿼리와 정보를 탈취하기 위한 쿼리문을 Union 연산자를 통해 실행시킨다.
- 데이터 형식과 컬럼 수가 일치하면 Union 연산자를 이용해 데이터를 가져올 수 있다.
SELECT uid FROM user_table WHERE uid='' UNION SELECT upw FROM user_table WHERE uid='admin' -- and... |
참고
https://www.baeldung.com/sql-injection
방어하는 방법
- Parameter Binding (preparestatement 사용)
- 순수한 Query String 을 사용하는 것이 아니라 Parameter Bindling 을 사용하면 피할 수 있다.
- mybatis에서 $를 사용하지 않고 #을 사용
- SQL 관련 에러가 발생했으르 때 해당 에러 메시지를 표시하지 않도록 한다.
Spring JPA 에서의 SQL injection 공격
Request Parameter 에 ' or 1'='1
을 덧 붙여 보내게 되면 서버에 저장된 모든 회원 정보를 가져올 수 있다.
http://localhost:8080/accounts?customerId=abc%27%20or%20%271%27=%271 |
저장된 회원 정보
|
Controller
customerId 파라미터로 넘어온 데이터를 이용해 데이터 베이스에 저장된 회원 정보를 불러 오도록 한다.
|
Repository
- Controller 에서 넘겨준 customerId 를 이용해 SQL 을 작성하고 작성된 SQL 을 이용해 데이터베이스에 저장된 회원 정보를 가져온다.
- Parameter 를 바로 받아 SQL 을 생성하는 이 부분에서 SQL Injection 문제가 발생하게 된다.
public List<AccountDTO> unsafeJpaFindAccountsByCustomerId(String customerId) { |
로그
로그를 확인해 보면 Parameter 로 같이 넘어온 ' or 1'='1
이 붙어서 쿼리문이 생성된 것을 확인할 수 있다.
생성된 쿼리가 수행될 경우 데이터 베이스에 저장된 모든 회원 정보를 가져오게 된다.
결과적으로 모든 회원 정보가 반환되는 것을 확인할 수 있다.