[security] “Bobby Tables”XKCD 만화에서 SQL 삽입은 어떻게 작동합니까?

그냥보고 :

XKCD 스트립
(출처 : https://xkcd.com/327/ )

이 SQL의 기능은 무엇입니까?

Robert'); DROP TABLE STUDENTS; --

나는 둘 다 알고 '있고 --주석이지만 DROP, 같은 줄의 일부이므로 단어에 주석이 달리지 않습니까?



답변

학생 테이블을 떨어 뜨립니다.

학교 프로그램의 원래 코드는 다음과 같습니다.

q = "INSERT INTO Students VALUES ('" + FNMName.Text + "', '" + LName.Text + "')";

이것은 쿼리에 텍스트 입력을 추가하는 순진한 방법이며 보시 다시피 매우 나쁩니다 .

이름, 중간 이름 텍스트 상자 FNMName.Text ( Robert'); DROP TABLE STUDENTS; --) 및 성 이름 텍스트 상자 LName.Text (호출 Derper)의 값이 나머지 쿼리와 연결되면 결과는 실제로 두 개의 쿼리로 구분됩니다. 명령문 종결 자 (세미콜론). 두 번째 쿼리는 첫 번째 쿼리에 삽입 되었습니다. 코드가 데이터베이스에 대해이 쿼리를 실행하면 다음과 같습니다.

INSERT INTO Students VALUES ('Robert'); DROP TABLE Students; --', 'Derper')

일반 영어로 두 가지 쿼리로 대략적으로 번역됩니다.

이름 값이 ‘Robert’인 Students 테이블에 새 레코드를 추가하십시오.

학생 테이블 삭제

두 번째 쿼리 이후의 모든 내용 은 주석으로 표시됩니다 . --', 'Derper')

'학생의 이름은이 닫는의 댓글 아닌 문자열 분리 . 학생의 이름은 문자열이므로 가상 쿼리를 완료하려면 구문 적으로 필요합니다. 주입 공격은 주입 한 SQL 쿼리가 유효한 SQL 결과를 얻을 때만 작동 합니다 .

dan04astute comment에 따라 다시 수정 되었습니다 .


답변

이름이 변수에 사용되었다고 가정 해 봅시다 $Name.

그런 다음이 쿼리 를 실행하십시오 .

INSERT INTO Students VALUES ( '$Name' )

코드가 실수로 사용자가 변수로 제공 한 것을 배치하고 있습니다.

SQL 이되기를 원했습니다 .

학생의 가치관에 삽입하기 ( ‘ Robert Tables`)

그러나 영리한 사용자는 원하는 것을 제공 할 수 있습니다.

학생의 가치관에 삽입하기 ( ‘ Robert'); DROP TABLE Students; --‘)

당신이 얻는 것은 :

INSERT INTO Students VALUES ( 'Robert' );  DROP TABLE STUDENTS; --' )

--줄의 나머지 부분 만 주석으로 처리합니다.


답변

다른 사람들이 이미 지적했듯이, ');마지막 진술 은 닫히고 두 번째 진술이 이어집니다. PHP와 같은 언어를 포함한 대부분의 프레임 워크는 현재 하나의 SQL 문자열에 여러 명령문을 허용하지 않는 기본 보안 설정을 가지고 있습니다. 예를 들어, PHP에서는 mysqli_multi_query함수 를 사용하여 하나의 SQL 문자열에서만 여러 명령문을 실행할 수 있습니다 .

그러나 두 번째 명령문을 추가하지 않고도 SQL 삽입을 통해 기존 SQL 문을 조작 할 수 있습니다. 이 간단한 선택으로 사용자 이름과 비밀번호를 확인하는 로그인 시스템이 있다고 가정 해 봅시다.

$query="SELECT * FROM users WHERE username='" . $_REQUEST['user'] . "' and (password='".$_REQUEST['pass']."')";
$result=mysql_query($query);

당신이 제공하는 경우 peter사용자 이름으로 및 secret암호와 같은 결과 SQL 문자열은 다음과 같을 것이다 :

SELECT * FROM users WHERE username='peter' and (password='secret')

모든것이 괜찮아. 이제이 문자열을 암호로 제공한다고 가정하십시오.

' OR '1'='1

그런 다음 결과 SQL 문자열은 다음과 같습니다.

SELECT * FROM users WHERE username='peter' and (password='' OR '1'='1')

암호를 몰라도 모든 계정에 로그인 할 수 있습니다. 따라서 SQL 삽입을 사용하기 위해 두 개의 명령문을 사용할 필요는 없지만 여러 명령문을 제공 할 수 있으면 더 파괴적인 작업을 수행 할 수 있습니다.


답변

아니요, 'SQL의 주석이 아니라 구분 기호입니다.

엄마는 데이터베이스 프로그래머가 다음과 같이 요청했다고 가정했습니다.

INSERT INTO 'students' ('first_name', 'last_name') VALUES ('$firstName', '$lastName');

(예를 들어) $xxx형식을 확인하거나 특수 문자를 이스케이프하지 않고 변수 내용을 HTML 양식에서 직접 가져온 새 학생을 추가합니다 .

따라서 데이터베이스 프로그램이 $firstName포함되어 있으면 Robert'); DROP TABLE students; --DB에서 다음 요청을 직접 실행합니다.

INSERT INTO 'students' ('first_name', 'last_name') VALUES ('Robert'); DROP TABLE students; --', 'XKCD');

즉. insert 문을 일찍 종료하고 크래커가 원하는 악성 코드를 실행 한 다음 나머지 코드가 있으면 주석 처리합니다.

음, 나는 너무 느리다. 나는 주황색 밴드에서 나의 앞에 8 개의 대답을 벌써 본다. 🙂 대중적인 주제, 그것은 보인다.


답변

TL; DR

- 응용 프로그램은에 시도하지 않고,이 경우 '낸시'의 입력을 받아 들인다 - 같은 특수 문자를 이스케이프로, 입력을 살균 
학교 => INSERT INTO의 학생 VALUES ( '낸시' ); INSERT 0 1
   
  

-데이터베이스 명령으로의 입력이 조작 될 때 SQL 주입이 발생합니다 .-데이터베이스 서버가 임의의 SQL 
School 을 실행하게합니다 => 학생들에게 INSERT INTO VALUES ( 'Robert' ) DROP TABLE 학생 ; - '); INSERT 0 1 DROP 테이블
      
  
 

-학생 기록이 이제 사라졌습니다. 훨씬 더 나빠졌을 수도 있습니다! 
학교 => 선택 * 학생들 로부터 ; 
오류 :   관계 "학생" 존재 하지 않습니다   
라인 1 : 선택 * 학생들 로부터 ; ^   
                      

학생 테이블이 삭제 (삭제)됩니다.

( 이 답변의 모든 코드 예제는 PostgreSQL 9.1.2 데이터베이스 서버에서 실행되었습니다. )

무슨 일이 일어나고 있는지 명확히하기 위해 이름 필드 만 포함하는 간단한 테이블로 시도하고 단일 행을 추가하십시오.

학교 => CREATE TABLE의 학생 ( 이름 TEXT PRIMARY KEY를 ); 
주의 사항 : CREATE TABLE / PRIMARY KEY를 합니다 만들 암시 인덱스 "students_pkey"를 위한 테이블 "학생들은" CREATE TABLE의 
학교 => INSERT INTO 학생 VALUES ( '요' ); INSERT 0 1             
    
  

애플리케이션이 다음 SQL을 사용하여 데이터를 테이블에 삽입한다고 가정 해 봅시다.

INSERT INTO의 학생 VALUES ( '는 foobar' );  

foobar학생의 실제 이름으로 교체하십시오 . 일반적인 삽입 작업은 다음과 같습니다.

-입력 : Nancy 
school => 학생 INSERT INTO VALUES ( 'Nancy' ); INSERT 0 1   
  

테이블을 쿼리하면 다음과 같은 결과를 얻습니다.

학교 => 선택 * 학생들 로부터 ;   
 이름
-------
 남자
 낸시
( 2 ) 

Little Bobby Tables의 이름을 테이블에 삽입하면 어떻게됩니까?

-입력 : Robert '); DROP TABLE 학생; - 
학교 => 학생 INSERT INTO VALUES ( 'Robert' ); DROP TABLE 학생 ; - '); INSERT 0 1 DROP 테이블      
  
 

여기에 SQL 삽입은 명령문을 종료하고 별도의 DROP TABLE명령을 포함하는 학생 이름의 결과입니다 . 입력 끝에있는 두 개의 대시는 남은 코드를 주석 처리하여 오류가 발생할 수 있습니다. 출력의 마지막 행은 데이터베이스 서버가 테이블을 삭제했음을 확인합니다.

INSERT조작 중에 응용 프로그램이 특수 문자에 대한 입력을 점검하지 않으므로 임의의 입력을 SQL 명령에 입력 할 수 있습니다. 이는 악의적 인 사용자가 일반적으로 사용자 입력을 목적으로하는 필드에 따옴표와 같은 특수 기호를 임의의 SQL 코드와 함께 삽입하여 데이터베이스 시스템이이를 실행하도록하여 SQL  주입 을 수행 할 수 있음을 의미합니다 .

결과?

학교 => 선택 * 학생들 로부터 ; 
오류 :   관계 "학생" 존재 하지 않습니다   
라인 1 : 선택 * 학생들 로부터 ; ^   
                      

SQL 주입은 운영 체제 또는 응용 프로그램 의 원격 임의 코드 실행 취약점 과 동등한 데이터베이스 입니다. 성공적인 SQL 주입 공격의 잠재적 영향은 데이터베이스 시스템 및 응용 프로그램 구성에 따라 공격자가 데이터 손실 (이 경우와 같이)을 유발하거나 데이터에 대한 무단 액세스를 얻거나 실행하는 데 사용될 수 있습니다. 호스트 시스템 자체의 임의 코드

XKCD 만화에서 알 수 있듯이 SQL 주입 공격으로부터 보호하는 한 가지 방법은 특수 문자를 이스케이프 처리하는 등의 방법으로 기본 SQL 명령을 수정할 수 없으므로 임의의 SQL 코드가 실행될 수 없도록 데이터베이스 입력을 삭제하는 것입니다. SqlParameterADO.NET에서 사용하는 것과 같이 매개 변수화 된 쿼리를 사용하는 경우 SQL 주입을 방지하기 위해 최소한 입력이 자동으로 삭제됩니다.

그러나 응용 프로그램 수준에서 입력을 삭제해도 고급 SQL 주입 기술이 중단되지 않을 수 있습니다. 예를 들어, PHP 함수 를 우회하는 방법이 mysql_real_escape_string있습니다 . 추가 보호를 위해 많은 데이터베이스 시스템이 준비된 명령문을 지원 합니다 . 백엔드에서 올바르게 구현 된 경우 준비된 명령문은 데이터 입력을 의미 적으로 나머지 명령과 분리하여 처리하여 SQL 삽입을 불가능하게 할 수 있습니다.


답변

다음과 같이 학생 생성 방법을 순진하게 작성했다고 가정 해보십시오.

void createStudent(String name) {
    database.execute("INSERT INTO students (name) VALUES ('" + name + "')");
}

그리고 누군가 이름을 입력합니다 Robert'); DROP TABLE STUDENTS; --

데이터베이스에서 실행되는 것은 다음 쿼리입니다.

INSERT INTO students (name) VALUES ('Robert'); DROP TABLE STUDENTS --')

세미콜론은 삽입 명령을 종료하고 다른 명령을 시작합니다. -나머지 줄을 주석으로 처리합니다. DROP TABLE 명령이 실행됩니다 …

이것이 바인드 매개 변수가 좋은 이유입니다.


답변

작은 따옴표는 문자열의 시작과 끝입니다. 세미콜론은 문장의 끝입니다. 그래서 그들이 이와 같은 선택을하고 있다면 :

Select *
From Students
Where (Name = '<NameGetsInsertedHere>')

SQL은 다음과 같습니다.

Select *
From Students
Where (Name = 'Robert'); DROP TABLE STUDENTS; --')
--             ^-------------------------------^

일부 시스템에서는 select먼저 drop명령문 이 실행됩니다! 메시지는 다음과 같습니다. SQL에 값이 없습니다. 대신 매개 변수를 사용하십시오!