UNION [1]

DATE : 2023/11/29

UNION은 두 SELECT문 사이에 접속사 마냥 사용되는 연산자로

SELECT COL_NAME FROM TABLE 
UNION
SELECT COL_NAME FROM TABLE

앞뒤에 작성된 select문의 결과를 하나로 합쳐주는 기능을 담당한다.

말로만 들으면 이해가 안 될 수 있으니, member table을 가지고 예시를 들어보자!

우선 UNION Operator 뒤에 작성해줄 형태의 SELECT문 결과를 확인해보면

Query에 작성한 대로 test, 1234 라는 값을 가지는 column이 2개인 데이터가 만들어졌다.

이때 column의 개수는 SELECT문에 , 콜론 으로 구분해 나열한 데이터 개수만큼 생겨난다.

아무튼! 이 Query를 통해 우리는

SELECT문에 데이터를 나열해 실행하면 해당 데이터를 각각 갖는 COLUMN이 생성됨을 알았다.

그럼 다음 단계로, 이 Query를 어디에 사용할 것인지 살펴보자!


UNION은 앞에서 말했듯이 SELECT문의 결과를 합쳐주는 역할을 수행한다. 이 말은 즉

SELECT * FROM member WHERE id='hanxx' UNION SELECT * FROM member WHERE Id='mario'

이처럼 id & password를 반환하는 두 SELECT문 사이에 UNION을 작성하게 되면

(1) SELECT * FROM member WHERE id='hanxx'  = 'hanhxx':'hanhxx1234'
(2) SELECT * FROM member WHERE Id='mario'  = 'mario':'jumpjump!!'

(1) & (2)의 결과가 하나로 합쳐져

위와 같은 결과를 얻을 수 있게 된다는 뜻이다!

이때 SELECT문을 위에서 작성했던 대로 값을 임의로 넣어주면

이처럼 우리가 입력한 값과 UNION 앞에 작성된 SELECT문의 결과가 합쳐지게 된다.

그런데 만약 UNION 앞에 작성된 SELECT문의 결과가 없다면 어떻게 될까??

이를 확인하기 위해 일부러 ID 값을 비워 SELECT문을 실행해보았다.

결과는 사진에서 볼 수 있듯이 UNION 뒤에 작성된 SELECT문의 값만 반영되는 걸 확인할 수 있다.

이는 아주 중요한 포인트가 될 수 있는데..!!

뒷부분은 다음 POST에 이어서 😏😏😏

우리가 UNION 연산자를 이용한 Query를 입력했다고 상상해보면

ID : hanhxx' union select 'mario1','mario2
PASS : ???

맨 앞에 작성한 "hanhxx" 라는 값은 첫 번째 SELECT문으로 들어가게 된다.

그렇게 되면 우리는 hanhxx의 정보와 mario1, mario2가 합쳐진 결과를 만들게 되고

if($db_pass == $user_pass) { ... } else { ... }

비밀번호를 비교하는 과정에서는 먼저 수행되어 결과를 도출한 hanhxx의 비밀번호로

비교 연산이 실행될 것이다.

이는 결국 hanhxx의 비밀번호를 오류 없이 입력했을 경우,

hanhxx 계정으로 로그인하는 것일 뿐 우회를 위한 Query로 사용할 수 없다.

그.래.서

비밀번호를 비교하는 과정에서 ROW가 여러 개면 맨 위에 있는 ROW의 비밀번호로만

비교 연산에 사용되기 때문에

첫 번째 SELECT문의 ID 값을 비워버리고 UNION으로 우리가 원하는 값을

비밀번호 연산 과정에서 사용하도록 만들자! 는 것이다. 💡

현재 사용자가 hanhxx라고 할 때, hanhxx는 mario 계정으로 로그인 시도를 하는 상황이라 생각해보자.

ID : ' union select 'mario','hanhxx1234
PASS : hanhxx1234

고민 끝에 입력한 ID & PASSWORD는 위와 같았다.

식별과 인증이 분리되어 실행되는 로직이기 때문에, 우선 hanhxx가 입력한 ID로 SELECT문이 실행되었다.

SELECT문의 결과를 확인해보면, hanhxx가 입력한 값만 그대로 나오는 걸 볼 수 있다!!

이는 Query의 결과가 하나이기 때문에 hanhxx가 입력한 자신의 비밀번호가

결과로 반환 된 ROW의 비밀번호로 들어가게 되고

동시에, 로그인할 때 입력한 비밀번호 또한 hanhxx 자신의 것이기 때문에

결국 hanhxx가 입력한 비밀번호와 Query 결과로 얻어온 비밀번호가 일치하게 됨으로써

로그인에 성공할 수 있게 된다.

즉, 자신의 비밀번호를 이용해 mario의 계정으로 로그인 우회를 성공한 것이다!

이렇게 해서 식별과 인증을 따로 실행하는 로그인 로직에서의 우회 방법을 살펴보았다.

or, and 연산자를 이용한 경우의 Query 보다는 좀 더 어려울 수 있지만

UNION 연산자를 활용하는 방법이 있다는 걸 확실하게 얻어가자 🤗

Last updated