LINQ to entities中Where子句中的引号转义
本文关键字:转义 Where to entities LINQ 子句 | 更新日期: 2023-09-27 18:16:27
我想知道如何将LINQ中的引号转义到实体。
这是我的环境:实体框架5与Silverlight 5和WCF RIA服务,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),它总是引发一个异常。
使用FilterDescriptor和DomainDataSource做同样的事情。
重要提示:对于%
或双引号"
这样的字符,它不会引发任何异常。此外,如果操作符等于strict,则不会引发任何简单引号异常,如下所示。
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注入?我必须写几十行代码来管理过滤器吗?
EDIT:问题已在EF的MySQL提供程序的最后一个版本中解决。
对于您的确切问题的快速解决方案:
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注入攻击以及如何防止它们。
我找到了一个解决这个问题的方法。
首先,我要感谢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);
}