가장 신뢰할 수 있는 방법은 항상 매개변수화된 쿼리 또는 준비된 표현식(Prepared Statements)을 사용하는 것이며, 사용자 정의 값으로 단순히 문자열을 연결하여 쿼리를 형성하지 않는 것입니다.
더 복잡한 시나리오(프로시저 내의 동적 SQL)의 경우, 매개변수를 필터링하기 위한 특수한 이스케이프 메커니즘 및 화이트리스트(엄격한 필터링)를 적용하십시오.
cursor.execute('SELECT * FROM users WHERE login = %s', [login])
EXECUTE format('SELECT * FROM %I WHERE id = $1', tablename) USING id;
여기서 %I는 안전한 방법으로 테이블/칼럼 이름만 대체합니다.
다음 접근 방식이 숫자를 문자열에 삽입할 때 안전한가요?
EXECUTE 'SELECT * FROM users WHERE id = ' || user_input;
아니요! 숫자를 기대하더라도 공격자가 코드를 전달할 수 있습니다:
1; DROP TABLE users; — 쿼리가 실행될 것입니다. 따라서 항상 플레이스홀더와 입력 매개변수의 타입을 명시적으로 검증하십시오.
사례 1
직원 검색 양식은 애플리케이션 측에서 문자열 연결을 통해 WHERE 조건을 구성했습니다. 공격자가 입력한 값: ' OR 1=1 --, 모든 직원의 데이터를 출력하게 되었습니다. 나중에 비슷한 접근 방식으로 데이터 섹션이 삭제되었습니다. 결론: 중요한 매개변수를 연결하는 것은 항상 위험입니다.
사례 2
관리 인터페이스에서 보고서 선택시 테이블 이름이 사용자 필드에서 불러와져 SQL 쿼리에 삽입되었습니다. 사용자가 유효하지 않은 이름을 삽입하여 시스템 테이블에 접근할 수 있었습니다. 이후 고정된 이름만 허용하도록 했습니다(화이트리스트).
사례 3
e-commerce 프로젝트에서 동적 정렬을 할 때 사용자가 GET 매개변수로 필드 이름을 전달했습니다. 해커가 price; DELETE FROM orders; --를 입력하여 모든 주문이 손실되는 결과를 초래했습니다. 허용된 칼럼 이름 필터링 및 매개변수화된 쿼리 사용으로 문제를 해결했습니다.