사용자의 입력값이 데이터로 처리되지 않고, 개발자가 의도하지 않은 DB를 조작하는 SQL 쿼리(명령어)의 일부로 실행되는 웹 보안 취약점
my_user_id 같은 데이터(값)를 입력my_user_id 대신 admin' OR '1'='1 같은 명령어(쿼리문)를 입력사용자 입력을 검증 없이 문자열로 이어붙여(+ 또는 concat) 쿼리문을 만들 때 주로 발생함
공격자는 쿼리문의 구문(Syntax)를 깨뜨리는 특수문자를 삽입하여 쿼리를 조작함
공격자가 “어떻게” 정보를 빼내는지에 따라 유형이 나뉨.
공격자가 보낸 쿼리의 결과를 현재 웹 페이지 화면을 통해 직접 볼 수 있을 때 사용함
UNION 연산자는 두 개 이상의 SELECT문 결과를 하나로 합치는 명령어
공격자는 이를 악용해 원래 쿼리 결과에 추가로 다른 테이블의 데이터를 붙여서 탈취
고의로 SQL 쿼리 오류를 발생시켜, 반환되는 오류 메시지를 통해 데이터베이스의 구조(테이블명, 컬럼명 등)를 알아내는 방식
만약 서버가 DB 오류 메세지를 화면에 그대로 노출하도록 설정되어 있다면, 공격자는 이 오류 메세지를 통해 DB의 버전, 테이블 이름, 칼럼명 등 민감한 DB 구조 정보를 알아낼 수 있음
추론 방식, 서버가 공격 결과나 메세지를 전혀 보여주지 않고, 단지 정상/ 오류 페이지만 보여줄 때 사용하는 고난도 기법
공격자는 참/ 거짓 반응 또는 응답 시간의 차이를 이용해 데이터를 한 글자씩 빼냄
참 / 거짓일 때의 페이지 반응이 다른 점을 이용함
DB에 내장된 SLEEP(), WAITFOR 등의 함수를 사용해, 응답 시간을 기준으로 데이터를 유추
쿼리의 틀(Template) & 사용자 값(Data)을 분리해서 DB에 전송함.
DB는 쿼리 틀을 먼저 컴파일하고, 값은 나중에 대입하므로 입력값이 절대로 명령어로 해석되지 않음.
SELECT * FROM users WHERE id = ? AND pw = ?; 와 같이, 값이 들어갈 자리를 ? (placeholder)로 표시한 '쿼리 틀'을 DB로 보냄PreparedStatement (JDBC), Python의 cursor.execute(query, params), PHP의 PDO 등userRepository.findById("admin"); 처럼 객체지향 코드를 작성하면, 내부적으로 안전한 Prepared Statement를 생성하여 DB와 통신함.서버단에서 사용자의 입력이 예상된 형식인지 검사
DB에 접속하는 웹 애플리케이션 계정에 필요한 최소한의 권한만 부여함
웹사이트는 데이터를 읽고(SELECT), 쓰고(INSERT), 수정(UPDATE)할 뿐 테이블을 삭제(DROP)할 필요는 없음
DROP 권한을 아예 주지 않으면, 공격자가 DROP TABLE 쿼리를 주입해도 권한 없음 오류로 실패하게 됨