FlawOpen

flawopen.com/PHP의 SQL Injection/mysqli와 PDO

MySQLi와 PDO: 안전한 Prepared Statement

참고 페이지
간단한 답변

Prepared Statement는 SQL 명령을 고정하고 입력값을 별도로 보냅니다. 라벨이 붙은 칸을 채우는 것과 같습니다. PDO와 MySQLi 모두 가능합니다. 안전성은 라이브러리 이름이 아니라 올바른 값 바인딩에서 나옵니다.

두 API로 같은 쿼리를 안전하게 준비하기

위험 — 요청 데이터가 포함된 SQL
$userId = $_GET['id'];
$sql = "SELECT id, email FROM users WHERE id = " . $userId;

// Both calls execute the already-built SQL string:
$rows = $mysqli->query($sql);
$rows = $pdo->query($sql);
안전 — 두 API 모두 값 바인딩
// PDO
$stmt = $pdo->prepare(
    "SELECT id, email FROM users WHERE id = :id"
);
$stmt->execute(["id" => $userId]);

// MySQLi
$stmt = $mysqli->prepare(
    "SELECT id, email FROM users WHERE id = ?"
);
$stmt->bind_param("i", $userId);
$stmt->execute();

PDO의 주요 차이는 데이터베이스 이식성

PDO의 주요 차이는 데이터베이스 이식성

PDO는 여러 드라이버에 공통 인터페이스를 제공하고 MySQLi는 MySQL과 MariaDB를 대상으로 합니다. PDO만으로 SQL이 이식 가능해지지는 않습니다. 방언, 드라이버 동작, 기능은 다릅니다.

플레이스홀더 형식이 다릅니다

PDO는 드라이버에 따라 :id 같은 이름 지정 또는 ? 위치 지정 플레이스홀더를 지원합니다. 한 문장에서 섞지 마세요. MySQLi는 위치 지정 ?를 사용합니다. 둘 다 값은 바인딩하지만 테이블/열 이름, 키워드, 정렬 방향은 바인딩하지 못합니다.

PDO 준비 모드는 드라이버에 따라 다릅니다

PDO 드라이버는 네이티브 또는 에뮬레이트 준비를 사용할 수 있습니다. MySQL에서 PDO::ATTR_EMULATE_PREPARES는 지원되는 경우 에뮬레이션을 제어합니다. 네이티브 준비가 불가능하거나 실패하면 에뮬레이션으로 대체될 수 있습니다. 드라이버 문서를 따르세요. 이 설정은 보간된 SQL을 안전하게 만들지 않습니다. SQL을 고정하고 값을 바인딩하세요.

두 라이브러리 모두의 SQL Injection 방지 규칙

prepare()를 사용하고 신뢰할 수 없는 값을 모두 바인딩하세요. SQL 구문을 고정하고 동적 식별자는 서버의 엄격한 매핑이나 유한한 쿼리 변형에서 선택하세요. Prepared Statement는 행 접근을 인가하지 않으므로 필요한 경우 인증 사용자 범위로 쿼리를 제한하세요. LIKE에서 바인딩은 SQL 구문 주입을 막지만 리터럴 검색을 위해 이스케이프하지 않으면 %와 _는 와일드카드입니다.

PDO와 MySQLi 중 선택하기

자주 묻는 질문

PDO 이름 지정 플레이스홀더가 MySQLi의 ?보다 안전한가요?

아니요. 쿼리를 준비하고 값을 바인딩하면 둘 다 값을 안전하게 처리합니다. 이름 지정 방식은 읽기 쉬울 수 있지만 식별자를 바인딩하거나 권한 검사를 대신하지 않습니다.

PDO 에뮬레이트 준비를 항상 꺼야 하나요?

일괄적으로 그렇지는 않습니다. 드라이버 지원과 대체 동작이 다릅니다. 문서와 앱 요구를 확인하세요. 어떤 모드에서도 SQL 구조를 고정하고 값을 매개변수로 전달하세요.

Prepared Statement가 테이블명이나 열 이름을 바인딩할 수 있나요?

아니요. 매개변수는 값용이며 SQL 식별자나 키워드용이 아닙니다. 클라이언트 선택을 서버의 유한한 신뢰 SQL 조각에 매핑하세요.

참고 자료

함께 보기 SQL 인젝션(CWE-89): 동작 원리와 언어별 방어 방법 — flawopen.com NHibernate는 SQL Injection을 막을 수 있나요? MongoDB NoSQL Injection: 안전한 쿼리 필터 숫자 ID도 문자열 포맷팅으로 SQL Injection이 발생할 수 있나요? 매개변수화 쿼리란 무엇인가 Prisma $queryRaw는 SQL Injection에 안전한가요? Rails where() 문자열 보간은 안전할까요?