String interpolation in 2.0 is a breaking change when injecting parameters in invalid places
See original GitHub issueIn EF Core 1.x the following worked as expected:
var databaseName = "Customer";
this.Database.ExecuteSqlCommand($"ALTER DATABASE [{databaseName}] SET CHANGE_TRACKING = ON (CHANGE_RETENTION = 2 DAYS, AUTO_CLEANUP = ON)");
In EF Core 2.0 the new string interpolation feature extracts the “databaseName” and injects it as a parameter, but SQL Server doesn’t allow the database name to be parameterized so it throws an exception:
Exception message: User does not have permission to alter database '@p0', the database does not exist, or the database is not in a state that allows access checks.
ALTER DATABASE statement failed.
Stack trace:
System.Data.SqlClient.SqlException occurred
HResult=0x80131904
Message=User does not have permission to alter database '@p0', the database does not exist, or the database is not in a state that allows access checks.
ALTER DATABASE statement failed.
Source=Core .Net SqlClient Data Provider
StackTrace:
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite, String method)
at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite, String methodName)
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.Execute(IRelationalConnection connection, DbCommandMethod executeMethod, IReadOnlyDictionary`2 parameterValues)
at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteNonQuery(IRelationalConnection connection, IReadOnlyDictionary`2 parameterValues)
at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.ExecuteSqlCommand(DatabaseFacade databaseFacade, RawSqlString sql, IEnumerable`1 parameters)
at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.ExecuteSqlCommand(DatabaseFacade databaseFacade, FormattableString sql)
at Contoso.Web.Services.SqlDatabaseEventRepository.CustomerDataContext.Initialize() in C:\Code\Contoso.Web\Services\SqlDatabaseCustomerRepository\CustomerDataContext.cs:line 33
at Contoso.Web.Services.SqlDatabaseEventRepository.SqlDatabaseCustomerRepository.Initialize() in C:\Code\Contoso.Web\Services\SqlDatabaseCustomerRepository\SqlDatabaseCustomerRepository.cs:line 25
at Contoso.Web.ApplicationInitializer..ctor() in C:\Code\Contoso.Web\ApplicationInitializer.cs:line 13
Further technical details
EF Core version: Microsoft.EntityFrameworkCore.SqlServer version 2.0.0 Database Provider: Microsoft.EntityFrameworkCore.SqlServer Operating system: Windows 10 version 1703 IDE: Visual Studio 2017.3
Issue Analytics
- State:
- Created 6 years ago
- Comments:6 (4 by maintainers)
Top Results From Across the Web
Can you use a custom string interpolation character in Scala?
Is it possible to use a different interpolation character to avoid the double escape? val characterA = "Randolph" val characterB = "Mortimer" ...
Read more >String Interpolation in Java
String interpolation is a straightforward and precise way to inject variable values into a string. It allows users to embed variable references ...
Read more >String Interpolation in C# 10 and .NET 6
This “string interpolation” functionality enables developers to place a $ character just before the string; then, rather than specifying ...
Read more >Passing parameters to SQL queries
When parameters are used, in order to include a literal % in the query you can use the %% string: cur.execute("SELECT (%s %...
Read more >Preventing SQL Injection Attacks With Python
In this step-by-step tutorial, you'll learn how you can prevent Python SQL injection. You'll learn how to compose SQL queries with parameters, as...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
@smitpatel It’s not all all obvious to a user that this escapes:
but this does not:
There’s a lot of information telling people that this is safe now, but the actual overload and resolution rules make it very brittle and there are even a lot of refactorings (e.g. do this replacement once) that unwittingly break it, even introducing SQL injection rather silently. It’s much better, IMO, to tell users to explicitly parameterize.
We’ve very explicitly stayed away from doing this with Dapper because the messaging is so dangerous, and we see a lot more raw SQL than any other library. I posted a repo (that you can run) showing just some of the injection cases and some of the many ways users can easily screw this up: https://github.com/NickCraver/EFCoreInjectionSample/blob/master/Program.cs
If you provide only a
FormattableString
method and not astring
overload, problem solved, right?The method that takes a raw string could have the suffix
Raw
orUnsafe
.