Database

SQL Injection ( SQL 주입 )

Seung-o 2022. 5. 14. 20:16

1. 개요

평화롭게 개발을 하고 있던 어느 날 ..

한 유저로부터 게임 접속이 되지 않는다는 문의 메일을 받게 된다. 

빠르게 패킷 로그를 확인해보았고, 유저가 메일을 보낸 시간대에 DB 구문 에러가 발생한 패킷을 확인할 수 있었다.

 

2. 원인

원인은 바로 .. SQL Injection ....!

유저가 계정을 변경하면서, ( 실수인지 아닌지는 모르겠지만 ) 홑따옴표를 넣은 것이다.

(예) user@naver.com'

 

확인해보니, 로그인 로직 상에서 Raw query를 사용하는 부분이 있었다. 여기서 injection에 대한 처리를 따로 해주지 않아서 발생한 문제였던 것이다.

 

3. 해결

1) 우선 다른 Repository에서도 Injection 문제가 발생하는지 확인해보았다. 그 결과, Sequelize의 내부 함수( findOne 등 )를 사용하라 때는 문제가 없었지만 정확히 Raw query를 사용할 때만 문제가 발생했다.

 

2) Raw query 에 대해서 결국 모두 Escape 처리를 해주었다. 정말 다행히도 사내 Sequelize 버전에는 escape 함수가 있었고, 모든 Raw query에 대해 escape 처리를 진행했다. [참고]

 

sequalize.escape(@parameter)

 

3) 한 가지 재밌는 사실은 sequelize를 사용할 때 파라미터가 직접적으로 사용되지 않기만 하면 자동으로 escape 처리가 될 수 있다는 것이다.  가령, 프로시저 호출 시에 

sequelize.query('CALL PROCEDURE ?', { replacements: ['someProcedure'] });

다음과 같이 someProcedure 라는 파라미터를 replacements 옵션을 통해 실행시키면 놀랍게도 escape 처리가 된다. ( 이것은 sequelize 내부적으로 escape 과정을 거칠 수 있게 설계되었기 때문인 것 같다 )

 

4. 결론

 

1) 우선 Raw query를 사용하는 Legacy 코드를 제거하고 리팩토링의 필요성을 느꼈다.

 

2) 서버에서 로직을 개선했으면 한다. 가령, NestJs 사용할 경우, class-validator가 이메일 형식의 여부를 확인해주기 때문에 초기부터 이런 문제를 방지할 수 있었을 것이다. 

 

3) 보다 근본적으로는 이메일 변경과 가입에 대한 프로세스적인 개선의 필요성을 느꼈다. 가령, 현재 회사 어플리케이션은 로그인 시 비밀번호 확인 절차가 없는데, 이 경우 비밀번호를 오타 등으로 인해 잘못 입력한 유저는 나중에 재로그인이 어려워질 것이다. 

 

계정 변경도 마찬가지이다. 계정 변경이 이루어지기 전에 확인 문구를 띄어주면서 유저에게 재차 확인을 받는다면 조금 더 어플리케이션 사용 만족도가 증가하지 않을까? 

 

나는 이러한 사항을 정리하여 회사에 보고했고 현재는 차차 개선이 이루어지고 있다. 개발자는 코드쟁이가 아닌 문제를 해결하는 사람이라는 걸 다시 한 번 느낀다.

'Database' 카테고리의 다른 글

MYSQL HA & DR 토폴로지 - 토스ㅣSLASH 21  (2) 2023.12.06