본문 바로가기

web

[SQL] SELECT Query 특성에 따른 SQL Injection 기법


다음과 같은 테이블을 생성하겠습니다. "user" Column은 Char타입이고 "no" Column은 Int타입 입니다.



Records는 다음과 같이 2개를 넣겠습니다.



다음과 같은 방법으로 "admin"을 출력시킬 수 있습니다.



위 Query의 논리를 정확하게 이해하기 위해서는 다음의 사항들을 이해해야 합니다.


SELECT * FROM sql150 WHERE sleep(1) 라고 Query를 날리면 몇 초가 출력될까요?



위와 같이 1초가 아니라 2초가 출력 됩니다. 즉 Record마다 sleep(1) 함수가 적용된다음 2초가 출력되는 것 입니다. 

따라서 WHERE 이하 절의 값을 확인 하기 위해 Row마다 들어가서 검사하는 것 입니다.


다음으로 아래의 3가지 Query를 이해해야 합니다.



첫번째, SELECT * FROM sql150 WHERE 1=1 or sleep(1)의 실행 결과 모든 Records가 출력되고 sleep() 함수는 적용이 되지 않은 것을 확인 할 수 있습니다. MySQL은 Query 최적화를 위해 or 이전에 값이 True이면 or 이하 절을 확인하지 않는다는 것을 볼 수 있습니다.


두번째, SLECT * FROM sql150 WHERE 1=1 and sleep(1)에서는 Records가 출력되지 않고 2초후에 출력되는 것을 확인 할 수 있습니다. 이것은  MySQL에서는 함수가 정상 종료되면 "0"을 Return 해주게 됩니다. 그렇기 때문에 True and False가 되어 아무것도 출력되지 않는 것입니다.


세번쨰, SELECT * FROM sql150 WHERE user='admin' or sleep(1)에서는 "admin" 레코드만 1초 후에 출력되는 확인 할 수 있습니다. 이것은 "admin" Row를 만나면 True가 되어서 or 이하 절을 검사하지 않고 "admin" 레코드를 출력하고, 다른 Row에서는 "admin" 값이 없기 때문에 or 이하절의 sleep(1) 함수를 실행시키는 것입니다.


다시 처음의 Query에서 어떻게 "admin"만 출력되는지를 살펴 보겠습니다.



먼저 user='guest' 절에서 "guest" Record를 만나면 True가 반환이 되어 True=0 임으로 출력이 되지 않고, "admin" Record를 만나면 False가 반환되어 False=0 임으로 "admin" Record만 출력되게 됩니다.


이와 비슷한 논리로 다음의 Query를 만들 수 있습니다.



no=1234 절에서 "1234" Record를 만나면 True가 반환 되어 True<1 임으로 False가 되어 출력 되지 않고, "1234" 이외의 Record를 만나면 False가 반환 되어 False<1이 되면서 True가 되어 해당 Record가 출력되게 됩니다.



'web' 카테고리의 다른 글

[SQL] MySQL 대소문자 구분  (1) 2016.02.02
PHP Session 저장 원리  (5) 2016.02.01
[SQL] MySQL Automatic Type Cast  (0) 2016.01.19