SQL Injection(SQL인젝션) 공격에 방어적인 MySQL 함수 사용법
SQL 인젝션 방어를 위해서 sprintf 함수를 많이 사용 하곤 했는데요. 이건 스트링에 그대로 대입을 시켜 주는 방식으로 쿼리문 문자열이 변경되는 방식 입니다.
이 방식 말고 mysqli 함수에서 제공하는 기능이 이건 좀 다릅니다.
파라미터 값이 문자열로 들어가는 것이 아니라 조건 그대로 들어가도록 되어 있습니다. 그렇기 때문에 OR 1=1 이런것이 먹히질 않습니다.
# CREATE TABLE test.test1 ( hostname char(22), indate datetime, diskval int ) comment = 'test table';
$tableName = 'test.test1';
# 입력
$hostname = 'list2';
$diskval = 7702;
$sql = "INSERT INTO $tableName (hostname, indate, diskval) VALUES (?, NOW(), ?)";
$stmt = $dbcon->prepare($sql);
$rbind = $stmt->bind_param("si", $hostname, $diskval);
$rexec = $stmt->execute();
# 성공여부는 0 보다 크면 성공 또는 오류 코드가 있나 확인: $dbcon->errno
// $stmt->affected_rows
echo 'insert 성공: ' . $dbcon->affected_rows . PHP_EOL;
# 업데이트
$sql = "UPDATE $tableName SET indate=now(), diskval=? WHERE hostname=?";
$stmt = $dbcon->prepare($sql);
$rbind = $stmt->bind_param("is", $diskval, $hostname);
$rexec = $stmt->execute();
echo 'update 성공: ' . $dbcon->affected_rows . PHP_EOL;
# 여러개 가져오기
$sqlSelect = "SELECT * FROM $tableName WHERE hostname = ? LIMIT 2";
$stmt = $dbcon->prepare($sqlSelect);
$stmt->bind_param('i', $hostname);
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
print_r($row);
}
$stmt->close();
echo '=--------------------------------------------' . PHP_EOL;
# 여러개 가져오기 while로 돌 필요 없이 모두 가져온다.
$sqlSelect = "SELECT * FROM $tableName WHERE hostname = ? LIMIT 2";
$stmt = $dbcon->prepare($sqlSelect);
$stmt->bind_param('i', $hostname);
$stmt->execute();
$row = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
print_r($row);
$stmt->close();
echo '=--------------------------------------------' . PHP_EOL;
# 1개 가져오기
$sqlSelect = "SELECT * FROM $tableName WHERE hostname = ? and diskval=? LIMIT 2";
$stmt = $dbcon->prepare($sqlSelect);
$stmt->bind_param('ii', $hostname, $diskval);
$stmt->execute();
$row = $stmt->get_result()->fetch_assoc();
print_r($row);
$stmt->close();
기본적인 사용방법입니다.
bind_param 이것은 한라인에 모두 적어야 하며 두번째 부터 변수가 들어가야 합니다. 상수가 들어가면 오류가 발생 합니다.
sql 구문은 prepare 으로 들어가기 전까지는 얼마든지 변경해도 문제 되지 않습니다.
인서트나 업데이트의 경우는 성공여부를 오류가 있는지 없는지로 판단 하면 됩니다.
마지막에 close() 하여 반드시 닫지 않아도 문제가 생기거나 하지는 않습니다.
PHP는 프로그램이 짧아서 바로 자동 해제가 됩니다. 다만 프로그램이 쉘에서 백그라운드로 오래 실행되거나 할 때는 처리해줄 필요가 있겠습니다.