FlawOpen

flawopen.com/SQL Injection/ORM만으로 충분한가?

ORM을 쓰면 SQL 인젝션을 막기에 충분한가?

참조 페이지
짧은 답

ORM은 주문서에 따라 음식을 만드는 주방과 같습니다. 일반 쿼리 빌더는 값을 분리합니다. 원시 SQL 지름길은 별도의 통로이며 규칙도 다릅니다. 보간된 값을 신뢰하기 전에 API를 확인하세요.

위험 — FromSqlRaw SQL에 사용자 텍스트
var sql = $"SELECT * FROM dbo.Blogs WHERE Url = '{url}'";
var rows = await context.Blogs
    .FromSqlRaw(sql)
    .ToListAsync();
// User text is inserted into SQL before execution.
안전 — FromSql로 바인딩 (EF Core 7+)
var rows = await context.Blogs
    .FromSql($"SELECT * FROM dbo.Blogs WHERE Url = {url}")
    .ToListAsync();
// EF Core 7+: interpolation becomes a SQL parameter.

모든 ORM에 공통된 패턴

ORM 쿼리 빌더와 원시 SQL API는 동일한 보안 경계가 아닙니다. 공식 문서는 Django raw(sql, params), 실행 매개변수를 분리하는 SQLAlchemy text(), Rails 플레이스홀더 조건, EF Core 7+ FromSql / FromSqlInterpolated, GORM Raw(sql, args...), Prisma 태그 템플릿 $queryRaw의 안전한 값 바인딩을 설명합니다. API 동작은 서로 다릅니다. 별도 매개변수를 제공하면 FromSqlRaw를 안전하게 사용할 수 있지만 SQL 문자열에 사용자 텍스트를 넣으면 위험합니다. $queryRawUnsafe도 값을 따로 바인딩할 수 있지만 신뢰할 수 없는 문자열을 연결하면 위험합니다. 메서드 이름만으로 값 처리 방식을 알 수 없습니다. 각 API의 문서화된 방식으로 모든 값을 바인딩하세요. SQL 식별자와 쿼리 구조는 매개변수화할 수 없으므로 애플리케이션의 고정 허용 목록에서 선택하세요. 자세한 내용은 아래 가이드를 참고하세요.

"충분"이 실제로 요구하는 것

FAQ

원시 SQL 메서드는 항상 위험한가요?

아닙니다. 일부 원시 SQL API는 별도 전달된 값을 바인딩하고, 안전한 API는 보간된 값을 매개변수로 받습니다. EF Core 7+ FromSql은 FormattableString을 받지만 FromSqlRaw에는 매개변수를 별도로 전달해야 합니다. Prisma $queryRawUnsafe도 값을 바인딩할 수 있지만 직접 만든 SQL 텍스트를 정화하지는 않습니다. 메서드 계약을 확인하고 신뢰할 수 없는 값이 SQL 구조에 들어가지 않게 하세요.

참고 자료

함께 보기 SQL 인젝션(CWE-89): 동작 원리와 언어별 방어 방법 — flawopen.com Knex.js는 SQL Injection에 안전한가요? MyBatis ${}와 #{}: SQL Injection 방지 MySQLi와 PDO: 안전한 Prepared Statement NHibernate는 SQL Injection을 막을 수 있나요? MongoDB NoSQL Injection: 안전한 쿼리 필터 숫자 ID도 문자열 포맷팅으로 SQL Injection이 발생할 수 있나요?