학습
PHP PHP에서의 보안 실습
PHP PHP에서의 보안 실습 — 중급
PHP에서의 보안 실습
1. 도입 (왜 배워야 하는가)
웹 개발에서 보안은 매우 중요한 요소입니다. PHP는 서버 사이드 언어로서 많은 웹 애플리케이션의 백엔드에서 사용됩니다. 보안이 취약한 코드를 작성하게 되면 해커가 시스템에 침투하거나 사용자 정보를 탈취할 수 있는 심각한 문제가 발생할 수 있습니다. 예를 들어, 데이터베이스에 저장된 사용자 비밀번호가 암호화되지 않은 채로 저장된다면, 해커가 이 정보를 쉽게 탈취할 수 있습니다. 따라서 보안에 대한 이해는 실무에서 안전하고 신뢰할 수 있는 웹 애플리케이션을 개발하는 데 필수적입니다.
2. 핵심 개념 설명
2.1 SQL 인젝션 (SQL Injection)
SQL 인젝션은 악의적인 사용자가 SQL 쿼리를 조작하여 데이터베이스에 비정상적인 요청을 보내는 공격입니다. 이는 사용자 입력을 적절히 검증하지 않았을 때 발생합니다.
비유: SQL 인젝션은 마치 식당에서 주문할 때, 종업원이 "치킨" 대신 "치킨을 주문하지 마세요, 대신 돈을 빼앗으세요"라고 적힌 종이를 받는 것과 같습니다. 식당이 이 주문을 제대로 검증하지 않으면 문제가 생깁니다.
| 용어 | 설명 |
|---|---|
| 인젝션 | 외부에서 주입된 데이터로 시스템이 의도하지 않은 동작을 하게 만드는 것 |
| 쿼리 | 데이터베이스에 요청하는 명령어 |
2.2 크로스사이트 스크립팅 (XSS)
XSS는 공격자가 웹 페이지에 악성 스크립트를 삽입하여 사용자의 브라우저에서 실행되도록 하는 공격입니다. 이는 사용자가 신뢰하는 웹사이트에서 발생할 수 있습니다.
비유: XSS는 친구의 집에 가서 친구가 만든 음식을 먹는 것과 비슷합니다. 당신은 친구를 믿지만, 그 친구가 음식에 독을 넣었다면 당신은 위험에 처하게 됩니다.
3. 기본 코드 예제
SQL 인젝션 방지 기본 코드
<?php
// 데이터베이스 연결
$conn = new mysqli("localhost", "username", "password", "database");
// 사용자 입력
$user_input = $_POST['username'];
// SQL 쿼리 준비
$stmt = $conn->prepare("SELECT * FROM users WHERE username = ?");
$stmt->bind_param("s", $user_input); // 사용자 입력 바인딩
$stmt->execute(); // 쿼리 실행
$result = $stmt->get_result(); // 결과 받기
while ($row = $result->fetch_assoc()) {
echo $row['username']; // 사용자 이름 출력
}
$stmt->close(); // 준비된 문 닫기
$conn->close(); // 연결 종료
?>
실행 결과:
- 해당 사용자의 이름이 출력됩니다.
new mysqli(...): 데이터베이스에 연결합니다.$user_input = $_POST['username'];: 사용자로부터 입력받은 값을 저장합니다.$conn->prepare(...): SQL 쿼리를 준비합니다.$stmt->bind_param(...): 사용자 입력을 안전하게 바인딩합니다.$stmt->execute(): 쿼리를 실행합니다.while ($row = $result->fetch_assoc()): 결과를 반복하여 출력합니다.$stmt->close(): 준비된 문을 닫습니다.$conn->close(): 데이터베이스 연결을 종료합니다.- 문제점: 사용자가 입력한 값이 그대로 SQL 쿼리에 포함되어 SQL 인젝션 공격에 취약합니다.
- 문제점: 사용자가 악성 스크립트를 입력할 경우, 그것이 그대로 실행되어 XSS 공격이 발생할 수 있습니다.
- SQL 인젝션과 XSS 공격에 대한 이해는 웹 애플리케이션 개발에서 필수적입니다.
- 준비된 문을 사용하여 SQL 쿼리를 안전하게 실행해야 합니다.
- 모든 사용자 입력은 반드시 검증하고, 출력할 때는 적절히 이스케이프 처리해야 합니다.
- HTTPS와 SSL/TLS
- CSRF (Cross-Site Request Forgery) 방지
- 웹 애플리케이션 방화벽(WAF) 사용 방법
코드 설명:
4. 실전 활용 예제
쇼핑몰에서 장바구니 구현 시
장바구니에 상품을 추가할 때, 사용자가 입력한 상품 ID를 바탕으로 데이터베이스에서 상품 정보를 조회해야 합니다. 이때 SQL 인젝션을 방지하기 위해 준비된 문을 사용하는 것이 필수입니다.
<?php
// 장바구니에 상품 추가
$product_id = $_POST['product_id'];
// SQL 쿼리 준비
$stmt = $conn->prepare("INSERT INTO cart (user_id, product_id) VALUES (?, ?)");
$stmt->bind_param("ii", $user_id, $product_id); // 사용자 ID와 상품 ID 바인딩
$stmt->execute(); // 쿼리 실행
$stmt->close(); // 준비된 문 닫기
?>
사용자 피드백 처리
사용자가 남긴 피드백을 데이터베이스에 저장할 때도 XSS 공격을 방지하기 위해 HTML 특수 문자를 이스케이프 처리해야 합니다.
<?php
// 사용자 피드백 저장
$feedback = htmlspecialchars($_POST['feedback']); // XSS 방지
$stmt = $conn->prepare("INSERT INTO feedback (user_id, feedback) VALUES (?, ?)");
$stmt->bind_param("is", $user_id, $feedback); // 사용자 ID와 피드백 바인딩
$stmt->execute(); // 쿼리 실행
$stmt->close(); // 준비된 문 닫기
?>
5. 흔한 실수와 주의사항
실수 1: 사용자 입력 검증 미비
// 잘못된 코드
$sql = "SELECT * FROM users WHERE username = '".$_POST['username']."'";
실수 2: XSS 방지 미비
// 잘못된 코드
echo $_POST['feedback']; // 사용자 입력을 그대로 출력