
얼마 전 이전 작업을 맡은 사이트에서 검색창에 작은따옴표 하나를 넣자 데이터베이스 오류가 화면에 그대로 나타났다. 서버는 정상이고 트래픽도 적었지만, 검색어를 SQL 문장에 이어 붙이는 코드가 남아 있었다. 이런 문제는 서버 사양을 올려도 해결되지 않는다. 입력값이 쿼리의 구조를 바꿀 수 있는지가 먼저다.
sql 인젝션 보안 방법은 복잡한 장비를 들이는 일보다 애플리케이션의 쿼리 작성 방식을 고치는 데서 시작한다. 특히 로그인, 검색, 게시글 조회처럼 누구나 호출할 수 있는 기능부터 확인해야 한다.
입력값은 쿼리 문장과 분리한다
가장 먼저 볼 곳은 사용자가 보낸 값을 문자열로 연결해 SQL을 만드는 코드다. 아이디가 숫자일 것으로 예상해도 요청값을 그대로 붙이면 공격자가 조건문이나 주석 구문을 끼워 넣을 여지가 생긴다. 화면에서 숫자만 입력되게 막아 둔 것은 방어가 아니다. 요청은 화면을 거치지 않고도 보낼 수 있다.
조회 조건에는 준비된 문장과 바인딩 변수를 쓴다. 예를 들어 회원 번호로 한 건을 찾는다면 SQL에는 값이 들어갈 자리를 표시하고, 실제 번호는 별도 인자로 전달한다. 데이터베이스가 그 값을 명령어가 아닌 데이터로 처리하도록 만드는 방식이다. 조회뿐 아니라 등록, 수정, 삭제에도 똑같이 적용한다.
ORM을 쓰는 사이트도 안심할 수는 없다. ORM의 일반적인 조건 조회 기능은 값을 안전하게 전달하지만, 개발자가 원시 SQL 기능을 꺼내 문자열을 조합하면 같은 문제가 돌아온다. 코드 검색에서는 문자열 연결로 만든 쿼리, 검색 조건을 직접 덧붙이는 함수, 오래된 공통 데이터베이스 모듈을 우선 찾는다. 한 화면을 고쳤다고 끝낼 수 없는 이유다.
정렬 기준과 테이블 이름은 허용 목록으로 제한한다
바인딩 변수로 처리할 수 없는 값도 있다. 정렬에 쓰는 열 이름, 오름차순·내림차순 지정, 테이블 이름처럼 SQL의 구조를 이루는 부분이다. 이런 위치에 요청값을 그대로 넣지 말고, 서버 코드에 허용할 선택지를 고정한다.
예를 들어 게시글 정렬 메뉴가 최신순과 조회순 두 가지라면 요청값을 각각 등록일 열과 조회수 열에 대응시키면 된다. 예상하지 못한 값은 기본 정렬로 돌리거나 요청을 거절한다. 테이블 이름을 사용자가 고르게 해야 하는 기능이라면 실제 테이블명을 받는 대신 미리 정의한 선택 번호를 받는 편이 안전하다.
입력값 검증도 함께 둔다. 페이지 번호와 표시 건수는 정수로 변환한 뒤 범위를 제한하고, 회원 번호는 형식과 길이를 확인한다. 다만 검증만으로 SQL 인젝션을 막겠다는 설계는 위험하다. 허용 문자 규칙이 바뀌거나 누락된 경로가 생겨도 쿼리의 값은 계속 바인딩되도록 해야 한다. 검색어에 작은따옴표가 들어가는 것 자체는 정상적인 사용일 수 있다.
데이터베이스 계정 권한을 기능별로 줄인다
코드를 고쳐도 오래된 관리자 화면이나 예약 작업에서 취약한 쿼리가 발견될 수 있다. 그때 피해 범위를 줄이는 장치가 데이터베이스 계정 권한이다. 웹 애플리케이션이 쓰는 계정에 모든 테이블의 삭제 권한과 계정 관리 권한까지 줄 이유는 거의 없다.
읽기 전용 통계 화면이라면 조회 권한만 주고, 일반 게시판 서비스라면 필요한 테이블에 필요한 작업 권한만 준다. 운영용 계정과 애플리케이션 계정을 분리하고, 개발 환경에서 쓰던 높은 권한의 계정을 운영 서버에 그대로 올리지 않는다. 권한을 바꿀 때는 등록·수정·예약 작업이 실제로 동작하는지 확인해야 한다. 너무 급하게 권한을 걷어 내면 정상 기능부터 멈춘다.
오류 처리도 점검한다. 사용자 화면에는 쿼리문, 테이블명, 데이터베이스 계정명이 드러나지 않게 하고, 운영 로그에는 어떤 요청 경로에서 오류가 났는지 추적할 정보를 남긴다. 로그에 비밀번호나 인증 토큰, 검색어 원문을 무조건 쌓는 방식은 피한다. 오류를 숨기는 일과 원인을 추적할 수 있게 남기는 일은 함께 해야 한다.
배포 전후에 실제 요청으로 확인한다
수정한 코드가 안전한지는 정상 입력과 경계 입력을 같이 보내 확인한다. 검색어에 작은따옴표를 넣었을 때 오류가 나지 않는지, 숫자 자리에 문자를 보냈을 때 요청이 거절되는지, 정렬 옵션에 예상하지 못한 값을 넣어도 허용 목록 밖의 열이 사용되지 않는지를 본다. 로그인과 검색만 확인하지 말고 관리자 목록, 파일 검색, 보고서 다운로드처럼 조건을 조합하는 화면도 포함한다.
웹 방화벽은 수상한 요청을 줄이는 데 쓸 수 있지만, 정상적인 입력과 공격 문자열을 완벽하게 구분하지는 못한다. 차단 규칙을 추가했다면 정상 검색이 막히지 않는지도 봐야 한다. 취약한 쿼리를 그대로 둔 채 방화벽에만 기대면 규칙을 통과한 요청 한 건에 다시 노출된다.
배포 순서는 백업 확인, 코드 수정, 테스트, 배포 후 오류 로그 확인 정도로 잡는다. 백업은 복구를 위한 수단이지 SQL 인젝션을 막는 수단은 아니다. 사고 뒤에 백업을 꺼내도 같은 취약점이 남아 있으면 다시 뚫릴 수 있다. 트래픽이 작은 사이트라면 값 바인딩과 권한 분리, 정기적인 복구 확인만 제대로 해도 비싼 보안 상품보다 먼저 해결할 문제가 많다. 운영 현장에서는 이런 기본 설정의 빈틈이 더 자주 사고로 이어진다.
