SQL 인젝션은 여전히 실무에서 가장 빈번하게 발생하는 보안 위협 중 하나다.
Go 백엔드에서 ORM으로 GORM을 쓴다고 해도, 안전하지 않은 쿼리 작성은 여전히 인젝션 공격의 여지를 남긴다.
이번 글에서는 다음 내용을 상세히 다룬다.
✅ 목차
- SQL 인젝션이란?
- GORM에서 발생할 수 있는 인젝션 사례
- 안전한 쿼리 작성법
- 바인딩 방식
- Named Parameter 전략
- Struct 기반 조건
- Raw SQL 시 주의할 점
- 실전 방어 전략 요약
1. SQL 인젝션이란?
SQL 인젝션(SQL Injection)이란, 쿼리문에 사용자 입력값이 그대로 삽입되면서 악의적인 SQL이 실행되는 공격이다.
예를 들어 아래처럼 문자열을 직접 연결하면:
db.Exec("DELETE FROM users WHERE name = '" + userInput + "'")
사용자가 userInput에 anything'; DROP TABLE users; -- 같은 값을 넣으면, 전체 테이블이 삭제될 수도 있다.
즉, 쿼리문이 조작되는 것이다.
2. GORM에서도 발생할 수 있다
ORM을 쓴다고 해서 무조건 안전한 건 아니다. 아래처럼 쿼리를 조합하거나 값을 직접 넣으면 위험하다.
❌ 인젝션 가능한 코드 예시
db.Where("name = " + userInput).Find(&user)
또는
db.Exec("UPDATE users SET status = 'active' WHERE name = '" + userInput + "'")
- userInput이 SQL 조작 문자열이면 그대로 실행됨.
- ORM이 내부적으로 쿼리를 생성하긴 하지만, 문자열을 직접 조작하면 소용없다.
3. 안전한 쿼리 작성법
✅ 방법 1: 바인딩된 변수 사용
db.Where("name = ?", userInput).Find(&user)
- ? 자리에 안전하게 바인딩됨.
- SQL 인젝션 방지의 기본.
✅ 방법 2: Named Parameters 사용
GORM은 map[string]interface{} 또는 gorm.Named를 통해 Named Parameter를 지원한다.
- map 방식
db.Where("name = @name AND age = @age", map[string]interface{}{
"name": userInput,
"age": 20,
}).Find(&user)
- gorm.Named 방식
db.Raw("SELECT * FROM users WHERE name = @name", gorm.Named("name", userInput)).Scan(&user)
Named Parameter는 여러 값이 있을 때 가독성도 좋고 안전성도 높다.
✅ 방법 3: Struct 기반 조건
GORM에서는 struct 자체를 조건으로 쓸 수 있다.
type Filter struct {
Name string
Age int
}
db.Where(&Filter{Name: userInput, Age: 20}).Find(&user)
- 내부적으로 안전하게 필드 값을 추출해서 WHERE 절을 생성
- 단, zero value (0, "", false)는 조건에서 제외됨 (주의!)
4. Raw SQL 쓸 때 주의점
Raw SQL은 강력하지만, 인젝션 위험이 크기 때문에 반드시 바인딩을 써야 한다.
❌ 이렇게 쓰면 위험하다
db.Raw("SELECT * FROM users WHERE name = '" + userInput + "'").Scan(&user)
✅ 바인딩을 쓰자
db.Raw("SELECT * FROM users WHERE name = ?", userInput).Scan(&user)
또는
db.Raw("SELECT * FROM users WHERE name = @name", gorm.Named("name", userInput)).Scan(&user)
5. 실전 방어 전략 요약
방법 | 인젝션 방지 여부 | 가독성 | 추천도 |
? 바인딩 | ✅ 안전함 | 보통 | ★★★★☆ |
Named Parameters | ✅ 매우 안전함 | 높음 | ★★★★★ |
Struct 기반 조건 | ✅ 안전함 | 좋음 | ★★★★☆ |
Raw SQL 문자열 연결 | ❌ 매우 위험 | 낮음 | ☆☆☆☆☆ |
- ✅ 요약: 절대 문자열을 직접 쿼리에 붙이지 말고, 항상 ?, @name, struct를 이용해 바인딩하자.
🔚 마무리
GORM을 쓴다고 무조건 안전한 건 아니다.
쿼리를 어떻게 작성하느냐에 따라, SQL 인젝션을 막을 수도 있고 초래할 수도 있다.
신뢰할 수 없는 입력값은 절대 직접 쿼리에 삽입하지 말자.
작은 실수가 운영 DB를 위험에 빠뜨릴 수 있다.
'개발 > Go' 카테고리의 다른 글
[Gin] GORM 디버깅 & 에러 핸들링 완전정복 (59) | 2025.06.13 |
---|---|
[Gin] GORM으로 단위 테스트 잘하는 법 - 테스트 환경 구성부터 Mock까지 (70) | 2025.06.11 |
[Gin] GORM 마이그레이션 전략 - 자동 vs 수동 관리, 안전하게 스키마 관리하기 (35) | 2025.06.06 |
[Gin] GORM 성능 최적화 팁 - Preload, Select, Index 전략까지! (64) | 2025.06.04 |
[Gin] GORM 고급 기능 완전 정복 - Soft Delete, Hook, 트랜잭션까지! (99) | 2025.05.28 |