SQL 인젝션(SQL Injection)
SQL Injection
설명
SQL 인젝션은 사용자 입력값이 그대로 SQL 쿼리 문자열에 연결(concatenation)되거나 포맷팅되어 실행될 때 발생하는 취약점입니다. 개발자가 "SELECT ... WHERE id = " + userInput 과 같이 직접 쿼리를 문자열로 조립하면, 공격자는 1 OR 1=1, 1; DROP TABLE users-- 같은 값을 넣어 쿼리 구조를 조작할 수 있습니다. 이로 인해 인증 우회, 데이터 조회/수정/삭제, 테이블 삭제 등 심각한 공격이 가능해집니다.
잠재적 영향
데이터 조회 및 유출 (정보 노출): 공격자가 원래 볼 수 없는 다른 사용자의 개인정보, 계정 정보, 내부 설정값 등을 조회할 수 있습니다.
데이터 변조 및 삭제 (데이터 무결성 훼손): INSERT, UPDATE, DELETE, DROP 등의 명령을 악용해 데이터 조작, 대량 삭제, 테이블/스키마 삭제가 가능합니다.
인증/인가 우회 (권한 우회):
OR 1=1등의 조건을 주입하여 로그인 우회, 권한 체크 우회가 발생할 수 있습니다.서비스 장애 (서비스 거부): 대량 쿼리, 무한 루프성 쿼리, 대규모 삭제 등을 실행해 DB와 서비스 전체에 장애를 유발할 수 있습니다.
해결 방법
Prepared Statement 사용:
db.Query,db.QueryRow,db.Exec사용 시 문자열 더하기 대신?,$1등의 placeholder 를 사용하고 인자를 별도 파라미터로 전달합니다.ORM 또는 Query Builder 사용: GORM 등 검증된 ORM/Query Builder 를 사용해 직접 문자열로 SQL을 조립하는 일을 최소화합니다.
입력값 타입 검증: ID, 숫자 등은
strconv.Atoi같은 함수로 숫자로 변환하고, 변환 실패 시 에러 처리하여 문자열 그대로 쿼리에 넣지 않습니다.화이트리스트 적용: 컬럼명, 정렬 기준(order by) 등 동적 SQL이 꼭 필요하다면, 미리 정의된 값 집합(화이트리스트)에서만 선택 가능하게 합니다.
최소 권한 원칙: DB 계정에 불필요한 권한(예: DROP, ALTER 등)을 주지 않아, 인젝션 발생 시 피해를 줄입니다.
에러 메시지 관리: DB 에러를 그대로 사용자에게 노출하지 말고, 내부 로그에만 상세 정보를 남기고 사용자에게는 일반적인 메시지만 보여줍니다.
취약한 코드 및 안전한 코드 예시
취약한 코드
안전한 코드
설명:
취약한 코드:
unsafeUserDetailHandler함수는 HTTP 요청에서 받은id값을 아무 검증 없이 문자열로 사용해서"... WHERE id = " + userID형태로 SQL을 직접 조립합니다. 이 경우 공격자가/user?id=1 OR 1=1 --와 같이 입력하면 실제 실행되는 쿼리는SELECT ... WHERE id = 1 OR 1=1 --가 되어, 모든 사용자 정보가 조회될 수 있습니다. 더 나아가1; DROP TABLE users--같은 입력으로 데이터베이스 구조를 파괴하는 공격도 가능합니다.안전한 코드:
safeUserDetailHandler함수는 먼저strconv.Atoi로id값을 정수로 변환해, 숫자가 아닌 값은 바로 차단합니다. 이후 SQL 문은 고정된 문자열("SELECT ... WHERE id = ?")로 두고,userID값은db.QueryRow(query, userID)의 인자로 별도 전달합니다. 이렇게 Prepared Statement/placeholder 를 사용하면, 입력값은 단순한 데이터로만 처리되고 SQL 문법으로 해석되지 않아, 공격자가 어떤 문자열을 넣어도 쿼리 구조를 바꾸는 SQL 인젝션이 불가능해집니다.
참조
Last updated