Language/Java

Java - PreparedStatement란 무엇인가?

JaeHoney 2022. 5. 3. 22:15

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