Reading this interesting article about SQL injection prevention in EF Core, I found out that now an interpolated string may result in a FormattableString
.
Running this test code in .NET Core 2.2:
public static void Main()
{
var filter = "Mark'; DROP TABLE tbl; --";
Console.WriteLine(FromSql("SELECT * FROM tbl WHERE fld = '" + filter + "'"));
Console.WriteLine(FromSql($"SELECT * FROM tbl WHERE fld = {filter}"));
Console.WriteLine(FromSql(FormattableStringFactory.Create(
"SELECT * FROM tbl WHERE fld = {0}", filter)));
}
private static string FromSql(string sql) => sql;
private static string FromSql(FormattableString sql)
{
var formatArgs = sql.GetArguments();
for (var paramIndex = 0; paramIndex < sql.ArgumentCount; ++paramIndex)
formatArgs[paramIndex] = "@p" + paramIndex;
return sql.ToString();
}
is not giving what I expected:
SELECT * FROM tbl WHERE fld = 'Mark'; DROP TABLE tbl; --'
SELECT * FROM tbl WHERE fld = Mark'; DROP TABLE tbl; --
SELECT * FROM tbl WHERE fld = @p0
The second print should output like the last one.
Try this is fiddle.
What am I missing?
Your second call Console.WriteLine(FromSql($"SELECT * FROM tbl WHERE fld = {filter}"));
looks to be going to the FromSql(string sql)
overload instead of FromSql(FormattableString sql)
.
Just remove the FromSql(string sql)
method (and the first call to it),
and it will go as expected; see the modified Fiddle.
The compiler seems to translate
var q = $"SELECT * FROM tbl WHERE fld = {filter}";
to a string
.
String q = $"SELECT * FROM tbl WHERE fld = {filter}";`
Because of the string
type, a String.Format
has taken place.
From the documentation:
If an interpolated string has the type string, it's typically transformed into a String.Format method call .
Whereas explicitly specifying FormattableString
as in
FormattableString q = $"SELECT * FROM tbl WHERE fld = {filter}";
a FormattableStringFactory.Create
is being used.
From the documentation:
If an interpolated string has the type IFormattable or FormattableString, the compiler generates a call to the FormattableStringFactory.Create method.