Statement
자바에서 쿼리문을 사용할 때 java.sql 패키지에 있는 Statement를 사용한다. Statement는 SQL문을 실행할 때 사용하는 인터페이스이다.
Statement는 다음과 같은 동작 방식을 가진다.
PreparedStatement
PreparedStatement는 Statement를 상속하고 있는 Interface이다.
PreparedStatement는 내부적으로 Statement의 4단계 과정 중 첫 번째 parse 과정의 결과를 캐싱하고, 나머지 3가지 단계만 거쳐서 SQL문이 실행될 수 있게 한다.
PreparedState를 사용하면 구문 분석(parse)의 결과를 캐싱해서 과정을 생략할 수 있으므로 성능이 향상된다.
많은 분들이 아시고 계시길 PreparedStatement가 SQL Injection을 방어할 수 있다고 한다.
로그인 기능을 제공한다고 가정하자.
Statement를 사용하면 아래와 같은 문법으로 작성하게 된다.
String sql = "SELECT * FROM user WHERE id ="+id+" AND password="+password;
사용자가 id에 1을 입력했다면 sql은 "SELECT * FROM user WHERE id=1 AND password="+password 가 된다.
사용자가 id에 1이 아닌 "1 OR 1=1 --"을 입력했다고 가정하자. password에는 1을 입력했다고 가정하자.
그러면 SQL문은 다음과 같이 된다.
SELECT * FROM user WHERE id=1 OR 1=1 -- AND password=1;
여기서 --은 주석이기 때문에 password 검증은 사라지고 모든 유저 정보가 전부 나온다.
Statement는 이러한 문제점 때문에 SQL Injection에 취약하다.
반면 PreparedStatement의 경우 SELECT * FROM user WHERE id = ? AND password = ?;
형식으로 작성한다.
여기서 구문 분석을 캐싱하는 과정에서 ?를 필드값으로 알고 하나의 필드값으로 삽입해버린다.
즉, 사용자가 id에 "1 OR 1=1 --"을 삽입해도 지금까지 id 뒤에 오는 값은 하나의 필드값으로 분석했으므로 "1 OR 1=1 --"이 id를 비교하는 하나의 필드값으로 인식을 해버린다.
결과적으로 구문이 바뀌지 않고, id가 "1 OR 1=1 --"인 것이 없으므로 결과가 조회되지 않는다.
마무리
Prepared Statement를 사용할 수 없겠다고 생각이 드는 상황도 있다.
본인의 경우 초성 검색을 개발할 때 SQL문이 복잡해서 어쩔 수 없이 Statement를 사용했었다.
물론 그 경우는 테이블이 보안적으로 노출되어도 전혀 문제가 없는 테이블이라서 가능했었고, 요즘은 가능하면 ORM이나 Prepared Statement를 사용해서 풀어내는 것이 좋다고 본다.
Reference
'Language > Java' 카테고리의 다른 글
Java - 제네릭(Generic)은 무엇인가? 에 대한 정리! (1) (0) | 2022.05.08 |
---|---|
Java - ArrayList가 가변적일 수 있는 이유 (+ Size 지정하는 이유) (0) | 2022.05.07 |
Java - Perm 영역이 Metaspace로 바뀐 이유! [+ Heap Area, Native Memory 차이] (0) | 2022.04.29 |
Java - JVM 구성 요소와 역할 정리! (+ JIT 컴파일러, 인터프리터, 클래스 로더, 가비지 컬렉터란 무엇인가?) (0) | 2022.04.27 |
Java - JDK와 JRE 차이 정리! (0) | 2022.04.26 |