3

我想知道如何在 LINQ to Entity 中转义引号。

这是我的环境:带有 Silverlight 5 和 WCF RIA 服务的实体框架 5、MySQL 5.6 和 MySQLConnector 6.5.6。

我有以下查询:

DomainContext.Load<Product>(DomainContext.GetProductQuery()
                                         .Where<Product>(p => p.name.Contains(parameter))
                                         .Take<Product>(30));

如果参数变量包含引号',则会引发 MySQL 语法错误异常。无论采用何种方法(StartWith、Contains),它总是会引发异常。

使用带有DomainDataSource的FilterDescriptor也是如此。

重要提示:它不会引发任何异常字符,如%或双引号"此外,如果运算符等于严格,如下所示,它不会用简单的引号引发任何异常。

DomainDataSource.FilterDescriptors.Add(new FilterDescriptor("productName", FilterOperator.IsEqualTo, SelectedProductName));

或者

DomainContext.Load<Product>(DomainContext.GetProductQuery()
                                         .Where<Product>(p == parameter)
                                         .Take<Product>(30));

我插入数据没有任何困难。

任何帮助都感激不尽。谢谢你。

更新:我忘了提一些事情。

这是我在服务端的方法。

public IQueryable<Product> GetProduct()
{
    return this.ObjectContext.product;
}

我应该如何保护它免受 SQL 注入?我是否必须编写数十行代码来管理过滤器?

编辑:问题在 EF 的 MySQL 提供程序的最新版本中得到解决。

4

2 回答 2

0

对于您的确切问题的快速解决方案:

string cleanParameter = parameter.Replace("'", "\'")

或者

这里查看一个更通用的解决方案,该解决方案描述了 mysql_real_escape_string 的 C# 等效项。

string cleanParameter = MySQLEscape(parameter)

MySQLEscape 如提到的文章中所述:

private static string MySQLEscape(string str)
{
    return Regex.Replace(str, @"[\x00'""\b\n\r\t\cZ\\%_]",
        delegate(Match match)
        {
            string v = match.Value;
            switch (v)
            {
                case "\x00":            // ASCII NUL (0x00) character
                    return "\\0";   
                case "\b":              // BACKSPACE character
                    return "\\b";
                case "\n":              // NEWLINE (linefeed) character
                    return "\\n";
                case "\r":              // CARRIAGE RETURN character
                    return "\\r";
                case "\t":              // TAB
                    return "\\t";
                case "\u001A":          // Ctrl-Z
                    return "\\Z";
                default:
                    return "\\" + v;
            }
        });
}

旁注:您的代码听起来可能容易受到SQL 注入攻击。(如果没有更多的上下文,我无法判断)。本文介绍什么是 sql 注入攻击以及如何防止它们。

于 2013-06-01T14:58:16.977 回答
0

我找到了解决此问题的方法。

首先,我要感谢www.developpez.net的 tomlev 作为chamamo的解决方案,也感谢他的帮助。

这是法语讨论的直接链接 http://www.developpez.net/forums/d1349604/services-web/wcf-ria-services-injection-sql/

这是解决此问题的包装器的源代码。

    class MySqlQueryableWrapper<T> : IQueryable<T>
{
    private readonly IQueryable<T> _queryable;
    private readonly IQueryProvider _provider;

    public MySqlQueryableWrapper(IQueryable<T> queryable)
    {
        _queryable = queryable;
        _provider = new MySqlQueryProviderWrapper(queryable.Provider);
    }

    public Type ElementType
    {
        get { return _queryable.ElementType; }
    }

    public Expression Expression
    {
        get { return _queryable.Expression; }
    }

    public IQueryProvider Provider
    {
        get { return _provider; }
    }

    public IEnumerator<T> GetEnumerator()
    {
        return _queryable.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

class MySqlQueryProviderWrapper : IQueryProvider
{
    private readonly MySqlExpressionFixer _visitor = new MySqlExpressionFixer();
    private readonly IQueryProvider _provider;

    public MySqlQueryProviderWrapper(IQueryProvider provider)
    {
        _provider = provider;
    }

    public IQueryable CreateQuery(Expression expression)
    {
        return _provider.CreateQuery(_visitor.Visit(expression));
    }

    public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
    {
        return _provider.CreateQuery<TElement>(_visitor.Visit(expression));
    }

    public object Execute(Expression expression)
    {
        return _provider.Execute(_visitor.Visit(expression));
    }

    public TResult Execute<TResult>(Expression expression)
    {
        return _provider.Execute<TResult>(_visitor.Visit(expression));
    }

}

class MySqlExpressionFixer : ExpressionVisitor
{    
    protected override Expression VisitMethodCall(MethodCallExpression node)
    {
        if ((node.Method.Name == "Contains" || node.Method.Name == "StartsWith") &&
            node.Method.DeclaringType == typeof(string) &&
            node.Arguments.Count == 1)
        {
            var c = node.Arguments[0] as ConstantExpression;
            if (c != null)
            {
                string s = c.Value as string;
                if (s != null)
                {
                    s = s.Replace("'", "''");
                    node = Expression.Call(node.Object, node.Method, Expression.Constant(s));
                }
            }
        }

        return base.VisitMethodCall(node);
    }
}

这是一个例子。

public IQueryable<Product> GetProduct()
{
    return new MySqlQueryableWrapper<Product>(this.ObjectContext.product);
}
于 2013-06-06T15:22:19.563 回答