SQL 인젝션이 성공하는 취약한 코드와 안전한 코드
아래는 쿼리 문장에 문자열을 넣어주는 일반적인 방식으로 SQL 공격에 무척 취약한 방식의 예 입니다.
보통 아래와 같은 문제가 발생하고 실무에선 쿼리를 보면 먼저 정보를 얻는것에서 시작을 합니다.
# SQL 인젝션이 성공하는 경우 (취약한 코드)
# 결과: SELECT * FROM users WHERE username = ''; DROP TABLE users; -- AND id = 123
$test11 = "'; DROP TABLE users; --";
$test22 = 123;
$sql = "SELECT * FROM users WHERE username = '$test11' AND id = $test22";
$result = $mysqliCon->query($sql);
값과 쿼리 명령을 별도로 분리해서 처리 하는 방식으로 SQL인젝션 공격에 해당하는것이 문자열에 들어가더라도 내부적으로 명령과 값을 분리해서 처리 하기 때문에 SQL 인젝션 공격이 먹히질 않습니다. 이 방식이 약간 더 복잡해 보이긴 하지만 외부에서 파라미터를 받는 방식이라면 이 방식을 사용해야 합니다.
# 안전한 코드 (bind_param 사용)
$sql = "SELECT * FROM users WHERE username = ? AND id = ?";
$stmt = $mysqliCon->getCon()->prepare($sql);
$stmt->bind_param("si", $test11, $test22);
$stmt->execute();
위 프로그램은 제가 만들어진 코드 이기 때문에 사용에 약간 다를 수 있지만 핵심은 bind_param 를 사용한 것입니다.
예전에 printf("select * from test.test where id='%s', $id) 이런 방식은 sql 인젝션 공격을 허용하는 방식입니다. 문자열에 변수 넣어주는것이기 때문입니다.
그렇기에 근본적으로 해결하는 방법은 bind_param 또는 PDO에 있는 bindParam, bindValue 를 사용하는 것입니다.
● SQL 인젝션(SQL Injection)
공격자가 웹 애플리케이션의 데이터베이스(SQL)를 조작할 수 있도록 악성 SQL 코드를 주입하는 공격 기법으로 공격이 성공하면 데이터 유출 조작 삭제 관리자 권한 탈취 심지어 서버 장악까지 가능 할 수 있는것으로 웹해킹에서 빈번한 방법중 하나임.
● SQL관련된 참고자료