- 자바 프로그래밍
- JDBC 프로그래밍(com.eomcs.jdbc)
- PreparedStatement 사용법
MySQL 에 root 계정으로 접속하기
사용자 목록 확인
원격에서만 접속할 수 있는 사용자 추가
원격에서만 접속할 수 있는 사용자를 만들기:
> CREATE USER '사용자명'@'%' IDENTIFIED BY '비밀번호';
=> 이 경우 study 사용자는 원격에서만 접속 가능하다.
MySQL 사용자에게 데이터베이스 사용 권한 부여
GRANT ALL ON 데이터베이스명.* TO '사용자아이디'@'서버주소';
ㄴ studydb 데이터베이스에 대한 모든 권한을 부여함
생성한 원격 접속이 가능한 사용자로 로그인
기본으로 사용할 테이블 설정
Statement 와 SQL 삽입 공격
jdbc_ex3_Exam0110.java
SQL 삽입 공격
=> 입력 문자열에 SQL 명령을 삽입하여 프로그램의 의도와 다르게 데이터를 조작하는 행위.
=> 사용자가 입력한 값을 가지고 SQL 문장을 만들 때 이런 문제가 발생한다.
=> 예를 들어 이 예제를 실행할 때 다음과 같이 입력해 보라!
제목? aaaa
내용? bbbb'), ('haha', 'hoho'), ('hehe', 'puhul
// Statement 와 SQL 삽입 공격
package com.eomcs.jdbc.ex3;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.util.Scanner;
public class Exam0110 {
public static void main(String[] args) throws Exception {
String title = null;
String contents = null;
try (Scanner keyboard = new Scanner(System.in)) {
System.out.print("제목? ");
title = keyboard.nextLine();
System.out.print("내용? ");
contents = keyboard.nextLine();
}
try (Connection con = DriverManager.getConnection( //
"jdbc:mysql://localhost:3306/studydb?user=study&password=1111");
Statement stmt = con.createStatement()) {
int count = stmt.executeUpdate(
"insert into x_board(title, contents) values('" + title + "','" + contents + "')");
// 위에서 사용자가 입력한 값을 가지고 SQL 문장을 만들면 다음과 같다.
//
// insert into x_board(title, contents) values('aaaa','bbbb'), ('haha', 'hoho'), ('hehe', 'puhul')
//
System.out.println(count + " 개를 입력하였습니다.");
}
}
}
게시물 관리 - 목록
jdbc_ex2_Exam0120.java
// 게시물 관리 - 목록
package com.eomcs.jdbc.ex2;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
// 다음과 같이 게시물 목록을 출력하라!
// 게시물 번호를 내림차순으로 정렬하라.
// ----------------------------
// 번호, 제목, 등록일, 조회수
// 2, aaa, 2019-1-1, 2
// 1, bbb, 2018-12-31, 3
// ----------------------------
public class Exam0120 {
public static void main(String[] args) throws Exception {
try (Connection con = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/studydb?user=study&password=1111");
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(
"select board_id, title, created_date, view_count from x_board order by board_id desc")) {
System.out.println("번호, 제목, 등록일, 조회수");
while (rs.next()) {
// 레코드에서 컬럼 값을 꺼낼 때 컬럼 번호를 지정하는 것 보다
// 컬럼의 이름을 지정하는 것이 유지보수에 더 좋다.
//
System.out.printf("%d, %s, %s, %d\n", //
rs.getInt("board_id"),
rs.getString("title"),
rs.getDate("created_date"),
rs.getInt("view_count"));
}
}
}
}
jdbc_ex3_Exam0110.java 실행
ㄴ Exam0110.java 실행 후 위와 같이 입력하면 아래와 같이 입력됨
=>
insert into x_board(title, contents) values('xxx','yyy'), ('하하하', 'okok')
=>
ㄴ 데이터가 2개가 입력됨
jdbc_ex2_Exam0120.java 이용하여 확인
ㄴ 11, 12 번 데이터가 2개 입력됨을 확인
PreparedStatement를 이용하여 SQL 삽입 공격 차단하기
jdbc_ex3_Exam0120.java
// PreparedStatement를 이용하여 SQL 삽입 공격 차단하기
package com.eomcs.jdbc.ex3;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.Scanner;
public class Exam0210 {
public static void main(String[] args) throws Exception {
String title = null;
String contents = null;
try (Scanner keyboard = new Scanner(System.in)) {
System.out.print("제목? ");
title = keyboard.nextLine();
System.out.print("내용? ");
contents = keyboard.nextLine();
}
try (Connection con = DriverManager.getConnection(
"jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");
PreparedStatement stmt = con.prepareStatement(
"insert into x_board(title,contents) values(?,?)")) {
// 위에서 준비한 SQL 문에 값을 설정한다.
// => ? : 값이 놓일 자리를 의미한다. 'in-parameter' 라 부른다.
// => in-parameter 에 들어갈 값의 타입에 따라 적절한 setXxx() 메서드를 호출한다.
//
stmt.setString(1, title);
stmt.setString(2, contents);
// => 이미 SQL 을 준비한 상태이기 때문에 실행할 때는 SQL를 줄 필요가 없다.
// => setXxx()로 설정된 값은 단순한 텍스트로 처리한 후
// SQL을 실행할 때 파라미터로 전달되기 때문에
// SQL 삽입 공격이 불가능 하다.
int count = stmt.executeUpdate();
System.out.println(count + " 개를 입력하였습니다.");
}
}
}
ㄴ PreparedStatement 이용하기
ㄴ ? 는 값이 놓일 자리를 의미하며 'in-parameter' 라고 부름
=>
=>
kkkkk
ddd'), ('kdkdk', 'kdkdk
ㄴ 이렇게 입력해도 setXxx()로 설정된 값은 단순한 텍스트로 처리한 후 SQL을 실행할 때 파라미터로 전달되기 때문에 SQL 삽입 공격이 불가능
jdbc_ex2_Exam0120.java 이용하여 목록 조회
ㄴ 13번 데이터만 입력됨
=>
게시물 관리 - 조회
jdbc_ex2_Exam0120.java
// 게시물 관리 - 조회
package com.eomcs.jdbc.ex2;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;
// 다음과 같이 게시물을 조회하는 프로그램을 작성하라!
// ----------------------------
// 번호? 1
// 제목: aaa
// 내용: aaaaa
// 등록일: 2019-1-1
// 조회수: 2
//
// 번호? 100
// 해당 번호의 게시물이 존재하지 않습니다.
// ----------------------------
public class Exam0130 {
public static void main(String[] args) throws Exception {
String no = null;
try (Scanner keyScan = new Scanner(System.in)) {
System.out.print("번호? ");
no = keyScan.nextLine();
}
try (Connection con = DriverManager.getConnection(
"jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(
"select * from x_board where board_id = " + no)) {
if (rs.next()) {
// 레코드에서 컬럼 값을 꺼낼 때 컬럼 번호를 지정하는 것 보다
// 컬럼의 이름을 지정하는 것이 유지보수에 더 좋다.
//
System.out.printf("제목: %s\n", rs.getString("title"));
System.out.printf("내용: %s\n", rs.getString("contents"));
System.out.printf("등록일: %s\n", rs.getDate("created_date"));
System.out.printf("조회수: %d\n", rs.getInt("view_count"));
} else {
System.out.println("해당 번호의 게시물이 존재하지 않습니다.");
}
}
}
}
ㄴ 13번 데이터에 내용에 입력한 그대로가 저장됨을 확인할 수 있음
PreparedStatement 를 이용하면 SQL 템플릿을 준비해둔 상태가 되기 때문에 실행할 때는 SQL를 줄 필요가 없음
=> 이를 통해 SQL 삽입 공격 방지