minwoorich / 2024-spring-jpa-study

3 stars 5 forks source link

JDBC의 PreparedStatement는 왜 SQL Injection 공격으로부터 안전한가요? #49

Open mulgoms2 opened 7 months ago

minwoorich commented 7 months ago

Statement 방식

String pw = 사용자가 입력한 pw;
String id = 사용자가 입력한 id;
String sql = "SELECT 이름, 주민번호 FROM USERS WHERE id="+ id +" AND password="+ pw;

PreparedStatement 방식

String pw = 사용자가 입력한 pw;
String id = 사용자가 입력한 id;
String sql = "SELECT 이름, 주민번호 FROM USERS WHERE id=? AND password=? ";
ps.setString(1,id);
ps.setString(2,pw);

SQL 인젝션 공격

사용자 입력 값

아이디 : minwoo-- 패스워드 : 1234 (틀린비밀번호)

Statement 사용시

String id = id;  // "minwoo --"
String pw = pw; // "1234"

String sql = "SELECT 이름, 주민번호 FROM USERS WHERE id="+**id**+"AND + "password="+ **pw**;
// String sql = "SELECT 이름, 주민번호 FROM USERS WHERE  id = minwoo -- AND password= 1234" ;
// '--' 은 SQL 에서 주석처리할때 사용한다. 즉," AND password = 1234" 는 전부 주석에 의해 무효화 된다.

주석을 제외한 DB에 최종 반영되는 쿼리 : SELECT 이름, 주민번호 FROM USERS WHERE id = minwoo;

악성 해커는 비록 틀린 비밀 번호를 입력했을지라도 minwoo 의 주민번호를 탈취해갈 수 있었다.

이 뿐만 아니라 만일 아이디로 minwoo OR 1=1 -- 를 입력했다면 WHERE 절이 '1=1' 이라는 조건식 때문에 무조건 true 가 저장되므로 minwoo 뿐만아니라 모든 사용자들의 주민번호를 탈취해 갈 수 있게된다.

SELECT 이름, 주민번호 FROM USERS WHERE id = minwoo OR 1=1 -- password=1234;
↓↓↓
SELECT 이름, 주민번호 FROM USERS WHERE true;

PreparedStatement 사용시

String id = id;  // "minwoo --"
String pw = pw; // "1234"

String sql = "SELECT 이름, 주민번호 FROM USERS WHERE id=? AND password=? ";
ps.setString(1,id);
ps.setString(2,pw);

PreparedStatement 의 경우 한번에 SQL 구문을 생성하는것이 아니라 각 파라미터 ('?' 부분) 마다 필드값을 바인딩 시킨다. 그렇기 때문에 id 에는 "minwoo--" 라는 값이 통째로 바인딩 되며 이를 JDBC 가 구문을 분석하면서 이런 조회할 때 id에 minwoo-- 로 저장된 데이터는 없으므로 조회 결과가 0 이나온다.

즉, SQL 인젝션 공격을 무효화 시킨것이다.