SQL Injection attacks in Entity Framework Core 2.0

Using an ORM framework isn't enough to prevent you from attacks like SQL injections. You have to use the framework with good practices and avoid bad code.

There is some (quick) highlights about good and bad practices using Entity Framework Core 2.0.

Using the FromSql()

Bad practice : use string concatenation

Good practice : use string interpolation

Using the ToSql()

With the ToSql(), be careful about overload

Nick Craver wrote some scenarios to illustrate the risk about the overload. The next samples are just some pastes of his work that you can find here.


static class Program
   {
    static void Main(string[] args)
    {
        string param = args.Length > 0 ? args[0] : "'Hey' Name, 1 IsAdmin --";

        using (var context = new TestContext())
        {
            WriteColor("This is parameterized, due to the FomattableString overload:");
            WriteLine(context.Users.FromSql($"Select 1 UserId, {param} Name, 0 IsAdmin").ToSql());
        }
    }
}

static class Program
   {
    static void Main(string[] args)
    {
        string param = args.Length > 0 ? args[0] : "'Hey' Name, 1 IsAdmin --";

        using (var context = new TestContext())
        {
            WriteColor("This is not parameterized, due to the var being string and using another overload:");
            var sql = $"Select 1 UserId, {param} Name, 0 IsAdmin";
            WriteLine(context.Users.FromSql(sql).ToSql());
        }
    }
}

static class Program
   {
    static void Main(string[] args)
    {
        string param = args.Length > 0 ? args[0] : "'Hey' Name, 1 IsAdmin --";

        using (var context = new TestContext())
        {
            WriteColor("This is also not parameterized, due to string using another overload:");
            string sqlString = $"Select 1 UserId, {param} Name, 0 IsAdmin";
            WriteLine(context.Users.FromSql(sqlString).ToSql());
        }
    }
}

static class Program
   {
    static void Main(string[] args)
    {
        string param = args.Length > 0 ? args[0] : "'Hey' Name, 1 IsAdmin --";

        using (var context = new TestContext())
        {
            WriteColor("This would appear to work, but is another injection path:");
            string injectionParam = "'" + param;
            string sqlQuotedString = $"Select 1 UserId, '{injectionParam}' Name, 0 IsAdmin";
            WriteLine(context.Users.FromSql(sqlQuotedString).ToSql());
        }
    }
}

static class Program
   {
    static void Main(string[] args)
    {
        string param = args.Length > 0 ? args[0] : "'Hey' Name, 1 IsAdmin --";

        using (var context = new TestContext())
        {
            WriteColor("This would appear to work, but is another injection path:");
            string injectionName2 = "'" + param;
            string quotedName = $"'{injectionName2}'";
            string sqlStringQuotedName = $"Select 1 UserId, {quotedName} Name, 0 IsAdmin";
            WriteLine(context.Users.FromSql(sqlStringQuotedName).ToSql());
        }
    }
}

This is it. Just a little post about a critical subject perfectly explained by the ASP.NET Monsters serie, and brillantly illustrated by Nick Craver.

November 21, 2017
  • Entity Framework Core 2.0
  • EF Core 2.0
  • SQL Injection
  • Channel9
  • Channel 9