English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

SQL 주입 (Injection)

이 튜토리얼에서는 일반적인 데이터베이스 취약점을 어떻게 수정할 수 있는지 배울 것입니다.

SQL注入이란 무엇인가요?

SQL注入은 공격자가 브라우저를 통해 애플리케이션 서버로 전달되는 데이터(예: 웹 폼 입력)에 악의적인 SQL 코드를 주입하거나 실행하는 공격입니다.

감사 정보와 같은 민감한 정보를 공개할 수 있으며, 사용자의 전화번호, 이메일 주소, 신용카드 정보 등을 포함할 수 있습니다. 공격자는 이를 통해 인증 절차를 회피하고 전체 데이터베이스에 대한 접근 권한을 얻을 수 있습니다. 그 작동 방식을 알아보겠습니다.

SQL注入은 어떻게 작동합니까?

다음은 Web 애플리케이션에서 사용자 이름과 비밀번호로 사용자 인증을 하는 간단한 SQL 예제입니다.

SELECT * FROM users WHERE username='username_val' AND password='password_val';

여기서는,username_valpassword_val각각 사용자가 입력한 사용자 이름과 비밀번호를 나타냅니다. 사용자가 'john'으로 사용자 이름을 입력하고, ' 123”와 같은 비밀번호 값을 입력하면, 결과 문장은 다음과 같습니다:

SELECT * FROM users WHERE username='john' AND password='123;

그러나 가정해 보겠습니다. 사용자가 공격자라면, 입력 필드에 유효한 사용자 이름과 비밀번호를 입력하지 않고 다음과 같은 값을 입력했습니다: ' OR 'x'='x

이 경우, 위의 SQL 쿼리는 다음과 같이 구성됩니다:

SELECT * FROM users WHERE username='' OR 'x'='x' AND password='' OR 'x'='x';

이 문장은 유효한 SQL 문장입니다. WHERE 'x'='x'는 항상 true이므로, 쿼리는 다음과 같이 반환됩니다:users테이블의 모든 행입니다. 공격자가 작은 조치만으로 데이터베이스의 모든 감사 정보에 쉽게 접근할 수 있음을 볼 수 있습니다.

如果users如果表很大,并且包含数百万或更多行,则该单个语句还可能通过使系统资源超载而导致拒绝服务攻击(DoS攻击),并使您的应用程序对合法用户不可用。

警告:如果你的脚本生成一个DELETE또는UPDATE쿼리를 수행하면 SQL注入의 후遗症를 무시하거나 더 나아질 수 있습니다. 공격자는 테이블에서 데이터를 제거하거나 모든 행을 영구적으로 변경할 수 있습니다.

SQL注入 방지

항상 사용자 입력을 확인하고, 어떤 가정도 하지 마세요. 사용자 입력으로부터 SQL 문장을 직접 구성하지 마세요. PHP와 MySQL을 사용하는 경우 mysqli_real_escape_string() 함수를 사용하여 SQL 문장에서 사용할 수 있는 합법적인 SQL 문자열을 생성할 수 있습니다.

이는 PHP와 MySQL을 사용하여 사용자 인증을 수행하는 매우 기본적인 예제로, 사용자에서 입력을 받을 때 SQL注入을 방지하는 방법을 보여줍니다.

<?php
// 세션 시작
session_start();
 
/* MySQL 서버 연결을 시도합니다.
   MySQL 서버를 기본 설정으로 실행 중이라고 가정하세요(사용자 'root'는 비밀번호가 없습니다) */
$link = mysqli_connect("localhost", "root", "", "demo");
 
// 연결을 확인하세요
if($link === false){
    die("에러: 데이터베이스에 연결할 수 없습니다.");
}
 
// 사용자 입력을 대체하여 보안을 유지하세요
$username_val = mysqli_real_escape_string($link, $_POST['username']);
$password_val = mysqli_real_escape_string($link, $_POST['password']);
 
if(isset($username_val, $password_val)){
    // SQL 쿼리 실행을 선택하려면
    $sql = "SELECT * FROM users WHERE username='" . $username_val . "' AND password='" . $password_val . "'";
    if($result = mysqli_query($link, $sql)){
        if(mysqli_num_rows($result) == 1{
            // 사용자가 인증되었습니다. 여기서 작업을 수행해 주세요
            $row = mysqli_fetch_array($result);
            /*세션 변수에 저장된 값을 저장합니다
               이를 통해 나중에 동일한 세션 참조에서 사용할 수 있도록 저장합니다 */
            $_SESSION['user_id'] = $row['user_id'];
            $_SESSION['first_name'] = $row['first_name'];
            header('Location: welcome.html');
        }
            echo "에러! 잘못된 사용자 이름이나 비밀번호입니다.";
        }
    }
        echo "에러: 문제가 발생했습니다. 다시 시도해 주세요.";
    }
}
 
// 연결을 닫기
mysqli_close($link);
?>

ヒント:테스트 애플리케이션에서 수신한 데이터의 크기와 타입 또는 내용을 확인하고, 시스템 자원이 활용되지 않도록 적절한 제한을 시행합니다。