【问题标题】:SQL injection with Entity Framework Database.SqlQuery使用实体框架 Database.SqlQuery 进行 SQL 注入
【发布时间】:2017-05-29 08:28:18
【问题描述】:

在我的项目中,我用下面的示例代码定义了一个存储过程:

CREATE PROCEDURE [dbo].[Stored]
    @ParameterA AS varchar(128),
    @ParameterB AS varchar(128),
    @ParameterC AS varchar(400)
AS
BEGIN
    DECLARE @query AS Varchar(MAX)

    SET @query = 'SELECT *
                  FROM Table  
                  WHERE A = '''+ @ParameterA + ''

    IF @ParameterB = 'B'
    BEGIN
        SET @query = @query + ' AND C=''' + @ParameterC + ''
    END 

    EXECUTE sp_executesql @query
END

我通过以下代码使用实体框架调用此过程:

DBContext.Database.SqlQuery<Object>("Stored",
new SqlParameter("@p0", Param0),
new SqlParameter("@p1", Param1),
new SqlParameter("@p2", Param2)).ToList();

如果我用下面的字符串调用存储过程,我会生成一个 SQL 注入:

Param2 = "ABC' ; DROP TABLE Table2"

如何使用 Entity Framework 防止这种情况发生?

【问题讨论】:

  • 我建议您避免在 SQL 语句中使用所有形式的字符串连接,即使在存储过程中也是如此。此外,您可以通过过滤单词来清理输入,以便在执行查询之前在 EF 端删除这些 SQL 关键字。
  • 可能是related
  • 我认为你不能用 EF 本身阻止这种事情。我会考虑看大局msdn.microsoft.com/en-us/library/cc716760(v=vs.110).aspx
  • 为什么要使用这样的存储过程而不是让 EF 生成安全查询?如果Table 映射到一个实体,为什么不编写一个EF 查询来返回它,必要时使用不同的Where() 子句?
  • @Marco 你想做什么?为什么不在 LINQ 中写一个简单的context.Entities.Where(condition1)context.Entities.Where(condition2)?如果您想动态添加多个条件,甚至var query=context.Entities.Where(condition1);query=query.Where(condition2)

标签: c# sql-server asp.net-mvc entity-framework sql-injection


【解决方案1】:

为了避免/最小化 [the risk of] SQL 注入,Microsoft 制定了一些规则:https://docs.microsoft.com/en-us/sql/relational-databases/security/sql-injection

例如:

“永远不要直接从用户输入构建 Transact-SQL 语句。”

这意味着在这种情况下,我将使用参数化 sp_executesql 重写原始代码:

CREATE PROCEDURE [dbo].[Stored]
    @ParameterA AS varchar(128),
    @ParameterB AS varchar(128),
    @ParameterC AS varchar(400)
AS
BEGIN
    DECLARE @query AS Varchar(MAX)

    SET @query = 'SELECT *
                  FROM Table  
                  WHERE A = @prmA'

    IF @ParameterB = 'B'
    BEGIN
        SET @query = @query + ' AND C=@prmC'
    END 

    EXECUTE sp_executesql @query, N'@prmA VARCHAR(128), @prmC VARCHAR(128)', @prmA = @ParameterA, @prmC = @ParameterC
END

sp_executesql 参考:https://docs.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-executesql-transact-sql

【讨论】:

    【解决方案2】:

    你不能

    底层 SQL 过程有缺​​陷,是一场安全噩梦。您无法在其顶部的图层上修复它。您在 EntityFramework 中尽了最大努力,但它仍然不安全。您需要修复问题(SQL 过程),而不是在使用它的图层上应用创可贴。


    sp_executesql 对于需要动态 SQL 和绑定参数的过程来说似乎是一个很好的起点。

    【讨论】:

    • 感谢您的回答,但我无法重写我的存储过程。有一个库可以防止 Sql Injections?我可以使用正则表达式来验证输入参数吗?
    • @Marco 你的存储过程本身就是SQL注入。你必须放弃它。再多的黑客攻击(这就是那些“清理”库的内容)都无法保证它的安全。为什么在拥有 EF 时尝试使用存储过程? EF 和 LINQ 已经允许您动态指定条件
    • @Marco 。您可以使用各种创可贴来确保您的参数不包含 SQL 代码,但归根结底,这是一场军备竞赛。您将永远落后一步并不断更新。
    • 这是一个示例。真正的存储过程适用于大数据集,性能优于 EF 查询。
    • 负责该程序的人,使用D'Artagnan 作为姓氏,并针对他或她的错误跟踪器提交错误。
    【解决方案3】:

    您正在创建一个动态查询,并在其中连接参数。这导致了问题。

    不要使用动态查询,或者验证参数(如果它包含任何关键字或字符)

    您还可以根据参数将查询重写为IF-ELSE结构,因此您不需要动态查询。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-01-14
      • 1970-01-01
      • 2020-07-05
      • 1970-01-01
      • 1970-01-01
      • 2010-12-06
      • 1970-01-01
      相关资源
      最近更新 更多