MySQL에서 SQL Injection 방어 방법

 

웹 애플리케이션에서 가장 흔하게 발생하는 보안 위협 중 하나는 SQL Injection입니다. 공격자가 쿼리에 악의적인 SQL 구문을 삽입함으로써 데이터베이스를 조작하거나 민감한 정보를 탈취할 수 있습니다.

특히 MySQL을 사용하는 웹 서비스에서는 반드시 사전에 SQL Injection에 대한 방어 조치를 마련해야 합니다.

SQL Injection이 무엇인지, 그리고 MySQL에서 이를 안전하게 방어하는 다양한 방법을 소개합니다.

 


SQL Injection이란?

SQL Injection(이하 SQLi)은 웹 애플리케이션에서 사용자 입력값을 통해 SQL 구문을 조작해 데이터베이스를 공격하는 기법입니다.

예시:

  SELECT * FROM users WHERE id = '$id';
  

만약 $id1 OR 1=1을 입력하면 전체 사용자 정보를 가져올 수 있습니다.

 


Prepared Statement (준비된 구문) 사용

SQL Injection을 방지하는 가장 효과적인 방법은 Prepared Statement를 사용하는 것입니다. 이는 SQL 구문과 사용자 입력값을 분리해 처리하기 때문에 쿼리 구조가 조작되지 않습니다.

PHP 예시 (MySQLi)

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

PDO 예시

  $stmt = $pdo->prepare("SELECT * FROM users WHERE email = :email");
  $stmt->bindParam(':email', $email);
  $stmt->execute();
  

 

 


사용자 입력값 검증 및 필터링

사용자로부터 받은 모든 데이터는 신뢰하지 말고 입력값 검증(validation)을 수행해야 합니다.

  • 숫자는 is_numeric() 또는 intval()로 필터링
  • 이메일은 filter_var($email, FILTER_VALIDATE_EMAIL) 사용
  • 길이 제한, 허용 문자 제한 적용

 


ORM 및 프레임워크 사용

Laravel, Django, Spring 등 대부분의 프레임워크는 SQL Injection을 방지하는 ORM(Object Relational Mapping)을 제공합니다.
ORM을 사용하면 쿼리를 직접 작성하지 않고 객체처럼 데이터를 다루기 때문에 SQLi 위험이 줄어듭니다.

 


에러 메시지 숨기기

데이터베이스 에러 메시지는 공격자에게 중요한 단서가 됩니다. 에러를 노출하지 않도록 try-catch 문으로 감싸고, 사용자에게는 일반 메시지를 출력하세요.

 


최소 권한 원칙 적용

MySQL 사용자 계정은 꼭 필요한 권한만 부여해야 하며, SELECT만 필요한 서비스에는 INSERT, UPDATE 권한을 부여하지 않아야 합니다.

  GRANT SELECT ON mydb.users TO 'readonly'@'localhost';
  

 

 


웹 방화벽 (WAF) 도입

WAF(Web Application Firewall)는 SQL Injection과 같은 공격을 서버 앞단에서 차단해주는 장비 또는 서비스입니다. Cloudflare, AWS WAF, Nginx ModSecurity 등을 활용하면 보안성을 더욱 강화할 수 있습니다.

 


 

MySQL에서 SQL Injection을 방어하려면 입력값 검증, Prepared Statement, 권한 제한, 에러 감추기 등을 종합적으로 적용해야 합니다. 무엇보다도 "입력값을 그대로 쿼리에 사용하지 않는다"는 원칙을 철저히 지키는 것이 가장 중요합니다.

보안은 한 번의 설정으로 끝나는 것이 아닌, 지속적인 점검과 보완이 필요합니다.