【问题标题】:EF Core Execute SQL with parametersEF Core 使用参数执行 SQL
【发布时间】:2021-03-26 23:29:05
【问题描述】:

该应用是 .Net Core 3.1,使用 EF Core 3 和 Azure 上的 SQL Server

所以我试图在我的数据库中使用来自客户端的数据创建一个表,并且我希望避免 SQL 注入。

到目前为止,我已经尝试使用 FormattableString,根据doc,它可以安全地防止 SQL 注入:

public Task CreateTableAsync(string tableName, JSchema tableSchema)
    {
        return TransactionAsync(async () =>
        {
            // Get the fields for the table creation
            var fields = await ParseJSchemaForCreationAsync(tableSchema);

            var sql = "CREATE TABLE {0} (";

            var sqlParams = new List<object>
            {
                tableName
            };

            var first = true;
            var count = 1;

            foreach (var entry in fields)
            {
                // entry.Value is from code so it's safe againt injection
                sql += first ? $"{{{count}}} {entry.Value}" : $", {{{count}}} {entry.Value}";
                first = false;

                sqlParams.Add(entry.Key);
                count++;
            }

            sql += ");";

            var safe = FormattableStringFactory.Create(sql, sqlParams.ToArray());

            // Create the table
            await _dbContext.Database.ExecuteSqlInterpolatedAsync(safe);
        });
    }

但我有一个错误:“'@p0' 附近的语法不正确”,尽管它似乎生成了一个有效的查询(当我得到 sage 的值时: “创建表 sqlDataSourceGrainTest (Id uniqueidentifier NOT NULL PRIMARY KEY, CreatedAt datetime2(0), UpdatedAt datetimeoffset(3), FirstName nvarchar(4000), Birthdate date, XId uniqueidentifier, Datetime datetime2(0), Timestamp timestamp, Height decimal(18, 2), HasFoodAllergy bit, Age bigint);"

我也尝试过使用 SQLParameter(我更喜欢):

public Task CreateTableAsync(string tableName, JSchema tableSchema)
    {
        return TransactionAsync(async () =>
        {
            // Get the fields for the table creation
            var fields = await ParseJSchemaForCreationAsync(tableSchema);

            var sql = "CREATE TABLE @tableName (";

            var sqlParams = new List<SqlParameter>()
            {
                new SqlParameter
                {
                    ParameterName = "tableName",
                    Value = tableName,
                }
            };

            var first = true;

            foreach (var entry in fields)
            {
                sql += first ? $"@{entry.Key} {entry.Value}" : $", @{entry.Key} {entry.Value}";
                first = false;

                var sqlParam = new SqlParameter
                {
                    ParameterName = $"{entry.Key}",
                    Value = entry.Key
                };

                sqlParams.Add(sqlParam);
            }

            sql += ");";

            // Create the table
            await _dbContext.Database.ExecuteSqlRawAsync(sql, sqlParams);
        });
    }

但我遇到了错误:“'@tableName' 附近的语法不正确。”

有人可以帮我找到创建表格的正确方法吗?有没有规定不能用带参数的sql建表。

我还需要更新表格、插入记录和更新记录

谢谢

编辑:基于我尝试过的 DavidG 和 HoneyBadger 的回答:

public Task CreateTableAsync(string tableName, JSchema tableSchema)
    {
        return TransactionAsync(async () =>
        {
            // Get the fields for the table creation
            var fields = await ParseJSchemaForCreationAsync(tableSchema);
            var sql = $"CREATE TABLE {tableName} (";
            var sqlParams = new List<SqlParameter>();
            var first = true;

            foreach (var entry in fields)
            {
                sql += first ? $"@{entry.Key} {entry.Value}" : $", @{entry.Key} {entry.Value}";
                first = false;

                var sqlParam = new SqlParameter
                {
                    ParameterName = $"{entry.Key}",
                    Value = entry.Key
                };

                sqlParams.Add(sqlParam);
            }

            sql += ");";

            // Create the table
            await _dbContext.Database.ExecuteSqlRawAsync(sql, sqlParams);
        });
    }

但现在错误是“'@id' 附近的语法不正确”,这是第一个参数的名称

SQL 我看到:CREATE TABLE tableTests (@Id uniqueidentifier NOT NULL PRIMARY KEY, @CreatedAt datetime2(0), @UpdatedAt datetimeoffset(3), @FirstName nvarchar(4000), @Birthdate date, @XId uniqueidentifier, @Datetime datetime2(0), @Timestamp 时间戳, @Height decimal(18, 2), @HasFoodAllergy bit, @Age bigint);"

在创建表时我不能使用任何参数吗?

【问题讨论】:

  • SQL Server 不允许您为表名使用参数。
  • 您确定您发布的编辑错误准确吗?
  • 调试时tableName 的值是多少?似乎您的 tableName-参数是 "@tableName" - 或者这是一个“旧”错误。如果您通过@tableName,它将不起作用。您不能使用任何 sql 参数作为 tableName。您需要传递实际的表名(不带sql参数)
  • 抱歉,错过了我的编辑,现在的错误是“'@id 附近的语法不正确”。我在问题中添加了 SQL

标签: c# sql entity-framework-core


【解决方案1】:

对象名称不能是参数,所以你需要使用连接:

var sql = "CREATE TABLE " + tableName + " (";

我希望您的用户不会参与决定表的名称,因此 sql 注入应该不是问题。

【讨论】:

  • 我希望您的用户不参与决定表的名称,因此 sql 注入不应该成为问题一个简单的正则表达式应该可以做到这一点。即使不涉及用户,我猜在连接之前进行验证也没有错
  • @MatthiasBurger,确实,建议进行一些健全性检查。
  • 编辑了我的问题 :) 是的,用户可以选择表名,但有一些验证
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-03-04
  • 2020-06-22
  • 2019-08-04
  • 1970-01-01
  • 2021-06-23
  • 1970-01-01
  • 2019-04-30
相关资源
最近更新 更多