FlawOpen

flawopen.com/SQL Injection em C#/EF Core FromSqlRaw

O FromSqlRaw do Entity Framework Core é seguro?

Guia de referência
Resposta curta

Sim, se os valores permanecerem separados do texto SQL. FromSqlRaw aceita SQL bruto; concatenar ou interpolar uma entrada não confiável em sua string pode alterar a consulta. Use argumentos de parâmetros separados ou passe um FormattableString interpolado para FromSqlInterpolated (ou FromSql no EF Core 7+). Pense no parâmetro como um compartimento lacrado: o banco recebe o valor, não novas instruções SQL.

INSEGURO — a interpolação vira uma string comum
// A interpolação é avaliada primeiro como uma string.
var sql = $"SELECT * FROM Users WHERE Id = {id}";

// FromSqlRaw recebe texto SQL, não um FormattableString.
var query = context.Users.FromSqlRaw(sql);
SEGURO — os valores continuam como parâmetros
// EF Core 3–6: placeholder posicional e valor separado.
var byRawParameter = context.Users.FromSqlRaw(
    "SELECT * FROM Users WHERE Id = {0}", id);

// EF Core 3+: passe a interpolação para a API parametrizada.
var byInterpolation = context.Users.FromSqlInterpolated(
    $"SELECT * FROM Users WHERE Id = {id}");

// EF Core 7+: FromSql também recebe FormattableString.
var byFromSql = context.Users.FromSql(
    $"SELECT * FROM Users WHERE Id = {id}");

O detalhe contraintuitivo

FromSqlInterpolated recebe um FormattableString. O EF Core lê o formato e os argumentos e envia cada valor interpolado como um parâmetro separado do banco; não há interceptação em tempo de compilação. O EF Core 7 adicionou FromSql com o mesmo comportamento seguro para strings interpoladas. Versões anteriores usam FromSqlInterpolated. FromSqlRaw também é seguro quando placeholders como {0} correspondem a valores passados em argumentos separados. Uma string interpolada armazenada primeiro como string já perdeu os metadados dos parâmetros.

Parâmetros vinculam valores, não nomes de colunas

Um parâmetro do banco representa um valor, não o nome de uma tabela ou coluna, um operador SQL ou a direção da ordenação. Se a estrutura da consulta precisar variar, escolha cada identificador de uma lista fixa permitida no código da aplicação; não tente parametrizar identificadores nem substitua essa lista por filtros de caracteres. Revise também autorização e custo da consulta: uma coluna válida ainda pode expor campos sensíveis ou provocar varreduras caras.

Como revisar sua base de código

rg -n -g '*.cs' '(FromSqlRaw|FromSqlInterpolated|FromSql)\s*\(' .
Em cada chamada, confira a sobrecarga e o tipo do argumento. Rastreie dados não confiáveis para encontrar concatenação, interpolação enviada a FromSqlRaw ou FormattableString convertido em string; analise identificadores dinâmicos separadamente.

Perguntas frequentes

FromSqlRaw é seguro quando recebe parâmetros?

Sim, quando o SQL contém placeholders e os valores são passados como argumentos separados, por exemplo FromSqlRaw("... {0}", value). Não concatene nem interpole primeiro o valor na string SQL.

Por que FromSqlInterpolated é seguro com uma string interpolada em C#?

Ele recebe um FormattableString, que preserva o formato e os valores separadamente. O EF Core transforma cada valor em um parâmetro do banco. Se a interpolação for atribuída primeiro a uma string ou passada para FromSqlRaw, essa proteção se perde.

Parâmetros podem substituir nomes de tabelas ou colunas?

Não. Parâmetros representam somente valores. Para identificadores dinâmicos, mapeie as escolhas do usuário para uma lista fixa de identificadores conhecidos e revise autorização e custo da consulta.

Referências

Veja também SQL Injection (CWE-89): como funciona e como evitar em todas as linguagens — flawopen.com FastAPI e SQL Injection: o que o Pydantic protege GORM Raw SQL: evite injeção SQL em Go É suficiente escapar aspas contra SQL Injection? Usar um ORM basta para prevenir SQL Injection? Knex.js é seguro contra SQL Injection? MyBatis ${} vs #{}: evitar SQL Injection