
고급 PHP 프로그래밍 – 웹 보안 – SQL 인젝션 방지
안녕하세요~ 😊
이번 시간에는 PHP 프로그래밍에서 절~대 빠뜨리면 안 되는 중요한 주제,
바로 SQL 인젝션(SQL Injection) 방지 방법에 대해 알아볼 거예요!
SQL 인젝션은 마치 입력창을 통해 침입하는 해커의 트로이 목마 같은 존재랍니다.
겉으론 평범한 입력처럼 보여도, 그 안에 악의적인 명령어가 숨어있을 수 있어요.
그럼 지금부터! 이런 공격을 막고 안전한 웹사이트를 만들기 위해 어떤 방법이 있는지
하나하나 알기 쉽게 설명드릴게요~ 👨💻🛡️
SQL 인젝션이란 무엇인가요?
SQL 인젝션은 공격자가 사용자의 입력값을 조작해서
SQL 쿼리문을 변형하거나 탈취·삭제 등의 악의적 명령을 실행하게 만드는 공격 방식이에요.
예를 들어 로그인 창에서 다음과 같은 쿼리가 있다고 가정해볼게요:
$id = $_POST['id'];
$pw = $_POST['pw'];
$sql = "SELECT * FROM users WHERE id = '$id' AND password = '$pw'";
그리고 사용자가 아이디에 다음을 입력하면?
id: admin' --
pw: (아무거나)
결과적으로 SQL은 이렇게 바뀌어요:
SELECT * FROM users WHERE id = 'admin' --' AND password = ''
--
는 주석 처리이기 때문에 뒷부분은 무시되고, 비밀번호 없이도 로그인이 될 수 있어요! 😱
SQL 인젝션의 위험성
위험 요소 | 설명 |
---|---|
데이터 유출 | 고객 정보, 계정 정보 노출 |
데이터 변조 | 가격, 등급, 포인트 등 조작 가능 |
데이터 삭제 | DROP TABLE users 같은 명령 가능 |
서버 권한 탈취 | DB 접속 계정으로 서버 명령 실행 가능성 |
SQL 인젝션은 단순한 장난이 아니라,
실제 기업의 존망을 결정할 수 있는 중대한 보안 위협이에요.
어떻게 방지할 수 있을까요?
🔐 1. Prepared Statement (준비된 문장) 사용하기
가장 강력하고 권장되는 방법은 PDO 또는 MySQLi의 prepared statement를 사용하는 거예요.
✅ PDO 예제
$db = new PDO('mysql:host=localhost;dbname=testdb', 'root', '');
$stmt = $db->prepare("SELECT * FROM users WHERE id = :id AND password = :pw");
$stmt->bindParam(':id', $id);
$stmt->bindParam(':pw', $pw);
$stmt->execute();
$result = $stmt->fetchAll();
👉 입력값을 자동으로 이중 따옴표 처리하고, SQL과 데이터 분리해서
인젝션이 절대로 먹히지 않아요!
🔐 2. mysqli의 바인딩 사용
$conn = new mysqli("localhost", "root", "", "testdb");
$stmt = $conn->prepare("SELECT * FROM users WHERE id = ? AND password = ?");
$stmt->bind_param("ss", $id, $pw);
$stmt->execute();
$result = $stmt->get_result();
ss
는 문자열(string) 2개를 의미해요.
bind_param
은 타입까지 지정하므로 타입 안정성도 확보할 수 있어요.
🔍 3. 사용자 입력값 검증 및 필터링
입력값을 단순히 SQL에 넣기 전에,
형식이 맞는지, 이상한 문자열이 있는지를 먼저 확인하는 것도 중요해요!
$id = filter_input(INPUT_POST, 'id', FILTER_SANITIZE_STRING);
- 이메일이라면
FILTER_VALIDATE_EMAIL
- 숫자라면
FILTER_VALIDATE_INT
- 문자열이라면
addslashes()
등으로 이스케이프 처리도 고려해요 (하지만 임시방편!)
🚫 4. 직접 SQL 조립 금지!
아래와 같은 코드 스타일은 절대로 사용하면 안 돼요!
$sql = "SELECT * FROM users WHERE id = '$id' AND password = '$pw'";
이런 방식은 외부 입력값이 그대로 들어가기 때문에,
SQL 인젝션에 속수무책이에요. 이제는 구시대의 유산으로 생각하시면 돼요!
실전 예제: 안전한 로그인 처리
$db = new PDO('mysql:host=localhost;dbname=testdb', 'root', '');
$id = $_POST['id'];
$pw = $_POST['pw'];
$stmt = $db->prepare("SELECT * FROM users WHERE id = :id AND password = :pw");
$stmt->execute([':id' => $id, ':pw' => $pw]);
$user = $stmt->fetch();
if ($user) {
echo "로그인 성공!";
} else {
echo "아이디 또는 비밀번호가 틀렸습니다.";
}
사용자의 입력값이 아무리 조작되더라도,
쿼리문 구조는 절대 흔들리지 않아요!
추가 보안 팁 🛡️
항목 | 설명 |
---|---|
DB 계정 권한 최소화 | SELECT 전용 계정을 분리해서 사용 |
에러 메시지 노출 금지 | 쿼리 오류를 사용자에게 직접 보여주지 않기 |
입력 길이 제한 | 비정상적으로 긴 입력 방지 |
로깅 | 이상 요청 탐지 및 기록 |
웹방화벽(WAF) 적용 | 패턴 기반으로 SQL 인젝션 차단 가능 |
마무리 요약 🎯
구분 | 보안 효과 |
---|---|
PDO prepared statement | ★★★★★ (최강 추천) |
mysqli prepared statement | ★★★★☆ |
filter_input 검증 | ★★★☆☆ |
직접 SQL 문자열 조립 | ☆☆☆☆☆ (절대 금지!) |
마무리하며 😊
SQL 인젝션은 한 줄의 삽입문으로 데이터베이스를 털어버릴 수 있는 위험한 공격이에요.
하지만 PHP에서는 PDO나 mysqli의 prepared statement를 사용하면
그 어떤 인젝션도 뚫을 수 없는 강력한 방어선을 구축할 수 있답니다!
이제부터는 여러분의 코드에서도 require
, $_POST
, query
대신
“보안”을 먼저 생각하는 습관을 만들어보세요.
웹 보안은 예방이 최선이고, 방심은 금물이랍니다! 🔒✨
다음 시간에는 크로스사이트 스크립팅(XSS) 방지 방법에 대해 함께 알아볼게요~
오늘도 안전하고 멋진 코딩 되세요! 💪💻🧠🛡️