flawopen.com/C# SQL Injection/EF Core FromSqlRaw
Entity Framework Core의 FromSqlRaw는 안전한가요?
값이 SQL 텍스트와 분리되어 있으면 안전합니다. FromSqlRaw는 raw SQL을 받으므로 신뢰할 수 없는 입력을 문자열에 연결하거나 보간하면 쿼리가 바뀔 수 있습니다. 별도의 매개변수 인수를 사용하거나 보간 결과인 FormattableString을 FromSqlInterpolated(또는 EF Core 7+의 FromSql)에 전달하세요. 매개변수는 봉인된 값 슬롯과 같습니다. 데이터베이스에는 값만 전달되고 새 SQL 명령은 전달되지 않습니다.
// 보간은 먼저 문자열로 평가됩니다. var sql = $"SELECT * FROM Users WHERE Id = {id}"; // FromSqlRaw에는 SQL 텍스트가 전달되며 FormattableString이 아닙니다. var query = context.Users.FromSqlRaw(sql);
// EF Core 3–6: 위치 placeholder와 별도 값. var byRawParameter = context.Users.FromSqlRaw( "SELECT * FROM Users WHERE Id = {0}", id); // EF Core 3+: 보간 문자열을 매개변수 API에 전달하세요. var byInterpolation = context.Users.FromSqlInterpolated( $"SELECT * FROM Users WHERE Id = {id}"); // EF Core 7+: FromSql도 FormattableString을 받습니다. var byFromSql = context.Users.FromSql( $"SELECT * FROM Users WHERE Id = {id}");
헷갈리기 쉬운 핵심
FromSqlInterpolated는 FormattableString을 받습니다. EF Core는 형식과 인수를 읽어 보간된 각 값을 별도의 데이터베이스 매개변수로 전송하며, 컴파일 시점에 가로채는 방식이 아닙니다. EF Core 7에는 같은 안전한 보간 동작을 제공하는 FromSql이 추가되었습니다. 이전 버전에서는 FromSqlInterpolated를 사용하세요. FromSqlRaw도 {0} 같은 placeholder에 해당하는 값을 별도 인수로 전달하면 안전합니다. 보간 문자열을 먼저 string 변수에 저장하면 매개변수 메타데이터가 이미 사라집니다.
매개변수는 값을 바인딩하며 열 이름은 바인딩하지 않습니다
데이터베이스 매개변수는 값을 나타내며 테이블명, 열 이름, SQL 연산자 또는 정렬 방향을 나타내지 않습니다. 쿼리 구조를 바꿔야 한다면 애플리케이션 코드의 고정 allow-list에서 식별자를 선택하세요. 식별자를 매개변수화하려 하거나 문자 필터링으로 allow-list를 대체하지 마세요. 권한과 쿼리 비용도 확인해야 합니다. 유효한 열도 민감한 데이터를 노출하거나 비용이 큰 스캔을 일으킬 수 있습니다.
- ✓값에는 직접 보간하는 FromSqlInterpolated/FromSql 또는 별도 매개변수를 쓰는 FromSqlRaw를 사용하세요.
- ✓연결하거나 보간한 사용자 데이터를 FromSqlRaw에 전달하지 마세요. FormattableString을 먼저 string으로 변환하지 마세요.
- ✓동적 식별자는 고정 allow-list에서만 선택하세요. 해당 필드의 접근 권한과 적절한 인덱스 여부를 별도로 확인하세요.
- ✓LINQ로 쿼리를 명확하게 표현할 수 있으면 우선 사용하세요. 매개변수화는 SQL 구문 인젝션을 막지만 권한이나 비즈니스 규칙을 적용하지는 않습니다.
코드베이스 확인 방법
rg -n -g '*.cs' '(FromSqlRaw|FromSqlInterpolated|FromSql)\s*\(' .자주 묻는 질문
SQL에 placeholder가 있고 값을 별도 인수로 전달하면 안전합니다. 예: FromSqlRaw("... {0}", value). 값을 먼저 SQL 문자열에 연결하거나 보간하지 마세요.
FormattableString을 받아 형식과 값을 분리해 보존하기 때문입니다. EF Core는 각 값을 데이터베이스 매개변수로 바꿉니다. 먼저 string에 저장하거나 FromSqlRaw에 전달하면 보호가 사라집니다.
아니요. 매개변수는 값만 나타냅니다. 동적 식별자는 사용자 선택을 고정된 식별자 allow-list에 매핑하고 권한과 쿼리 비용을 검토하세요.