小巧玲珑和SQL注入

时间:2012-11-30 21:28:51

标签: .net orm .net-3.5 dapper

Dapper如何帮助防止SQL注入?我正在测试不同的DAL技术,必须选择一个来保护我们的网站。我倾向于Dapper(http://code.google.com/p/dapper-dot-net/),但需要一些帮助来学习安全性。

3 个答案:

答案 0 :(得分:49)

  

Dapper如何帮助防止SQL注入?

这使得真的,真的易于完全参数化数据访问,而无需连接任何输入。特别是,因为您不需要跳过大量的“添加参数,设置参数类型,检查null ,因为ADO.NET具有糟糕的空值处理,冲洗/重复20个参数” ,通过使参数处理愚蠢方便。它还可以很容易地将行转换为对象,避免使用DataTable的诱惑...每个人都获胜。

来自评论:

  

还有......那个小巧玲珑实际上有什么帮助呢?

要回答,让我们以marc_s的回复为例,并以旧方式编写,假设我们必须以connection开头。那就是:

List<Dog> dogs = new List<Dog>();
using(var cmd = connection.CreateCommand()) {
    cmd.CommandText = "select Age = @Age, Id = @Id";
    cmd.Parameters.AddWithValue("Age", DBNull.Value);
    cmd.Parameters.AddWithValue("Id", guid);
    using(var reader = cmd.ExecuteReader()) {
        while(reader.Read()) {
            int age = reader.ReadInt32("Age");
            int id = reader.ReadInt32("Id");
            dogs.Add(new Dog { Age = age, Id = id });
        }
        while(reader.NextResult()) {}
    }
}

除了我严重过度,因为它还涉及广泛的问题,如:

  • null参数处理
  • null处理结果列
  • 使用序数列索引
  • 适应基础表的结构变化并输入
  • 结果列的数据转换(在各种基元,字符串,枚举等之间)
  • 对此列表中的“哦 - 如此常见”的特殊处理方案
  • 表示“执行”,特殊处理“将此单独应用于输入列表”
  • 避免愚蠢的错别字
  • 减少代码维护
  • 处理多个网格
  • 处理在单个网格中水平返回的多个对象
  • 使用任意ADO.NET提供程序(提示:AddWithValue很少存在)
    • 包括对Oracle等需要额外配置的特定支持
    • 可以很好地使用ADO.NET decoratos,例如“mini-profiler”
  • 内置支持缓冲(适用于小到中等数据;最小化命令持续时间)和非bufferesd(适用于大数据;最小化内存使用)访问
  • 由关心性能并且对数据访问和元编程“非常了解”的人进行优化
  • 允许您使用您选择的POCO / DTO / anon-type /无论参数和输出如何
  • 允许在输出不保证生成POCO / DTO时使用dynamic(对于多列)或基元等(对于单列)
  • 避免复杂的完全类型的ORM(如EF
  • )的开销
  • 避免像DataTable
  • 这样的弱类型图层的开销
  • 根据需要打开和关闭连接
  • 以及其他一系列常见问题

答案 1 :(得分:35)

您只需要像往常一样使用参数化查询。由于Dapper只是“原始”SQL和ADO.NET的“微小”(并且非常薄)扩展 - 只需使用参数化的ADO.NET查询和提供参数。

请参阅Dapper-Dot-Net网站上的此示例:

var dog = connection.Query<Dog>("select Age = @Age, Id = @Id", 
                                new { Age = (int?)null, Id = guid });

SQL查询使用参数 - 您将这些参数提供给“Dapper”查询。

总结一下:使用Dapper本身并不能帮助防止SQL注入本身 - 但是使用参数化 ADO.NET/SQL查询(并且这些查询完全由Dapper支持,没有问题)在所有)

答案 2 :(得分:-1)

是的,确保开发者的业务交易是每个开发人员的首要考虑。

为此,我总是更喜欢使用带有dapper的存储过程,并且我还使用包装方法来检查存储过程,以防止出现不必要的查询和单词:

private static bool IsStoredProcedureNameCorrect(string storedProcedureName)
{
    if (string.IsNullOrEmpty(storedProcedureName))
    {
        return false;
    }

    if (storedProcedureName.StartsWith("[") && storedProcedureName.EndsWith("]"))
    {
        return Regex.IsMatch(storedProcedureName,
                    @"^[\[]{1}[A-Za-z0-9_]+[\]]{1}[\.]{1}[\[]{1}[A-Za-z0-9_]+[\]]{1}$");
    }

    return Regex.IsMatch(storedProcedureName, @"^[A-Za-z0-9]+[\.]{1}[A-Za-z0-9]+$");
}

还可以使用验证器将不需要的查询作为参数:

public static partial class Validator
{
        private static readonly string[] Expressions = {
            @"^.*((?i)select).*((?i)from).*$",
            @"^.*((?i)insert into).*$",
            @"^.*((?i)update).*((?i)set).*$",
            @"^.*((?i)delete from).*$",
            @"^.*((?i)create database).*$",
            @"^.*((?i)create table).*$",
            @"^.*((?i)create procedure).*$",
            @"^.*((?i)create index).*$",
            @"^.*((?i)alter database).*$",
            @"^.*((?i)alter table).*$",
            @"^.*((?i)alter procedure).*$",
            @"^.*((?i)alter index).*$",
            @"^.*\b((?i)exec(ute)?)\b.*$",
            @"^.*((?i)shutdown with nowait).*$",
            @"^.*((?i)waitfor delay).*$",
            @"^.*((?i)drop table).*$"
        };

        public static bool DoesContainQuery(string input)
        {
            var inLowerCase = input.ToLower();
            return Expressions.Any(expression => Regex.IsMatch(inLowerCase, expression));
        }

        public static string ReplaceSqlCharacter(string parameter)
        {
            parameter = parameter.Replace(";", "").Replace("[", "").Replace("]", "").Replace("--", "")
                .Replace("_xp", "").Replace(@"/*", "").Replace(@"*/", "").Replace("@@", "");
            return parameter;
        }
    }

您还可以看到我的详细信息,答案为here