Search code examples
c#.net-coreformattablestring

Not able to use FormattableString


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?


Solution

  • 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.