${tableName}이라고 쓰고, tableName 변수에 users라는 값이 있는 경우SELECT * FROM users가 됨#{userId}라고 쓰면, 실제 쿼리는 SELECT * FROM users WHERE id = ?가 되고, userId 변수의 값은 별도로 쿼리에 삽입String query = "SELECT * FROM users WHERE username = '" + username + "'";username 변수에 "admin' --"와 같은 값이 들어간다면, 최종 쿼리는 "SELECT * FROM users WHERE username = 'admin' --'"가 되어 SQL 주석을 이용한 인젝션 공격이 가능#{변수}는 ? (placeholder)로 대체"SELECT * FROM users WHERE id = #{userId}"라는 쿼리는 "SELECT * FROM users WHERE id = ?"로 변환#{변수}에 해당하는 자리에 실제 변수의 값을 바인딩함? 자리에는 안전하게 바인딩된 실제 값이 들어 감PreparedStatement pstmt = connection.prepareStatement("SELECT * FROM users WHERE username = ?");
pstmt.setString(1, username);username에 "admin' --"가 들어가도, 이 값은 문자열 데이터로 처리되어 쿼리의 구조를 변경할 수 없음