我想知道如何逃避LINQ to Entities中的引号。
这是我的环境:使用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提供程序的最新版本中得到解决。
答案 0 :(得分:0)
快速解决您的确切问题:
string cleanParameter = parameter.Replace("'", "\'")
OR
查看here以获得更通用的解决方案,该解决方案描述了与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注入攻击。 (没有更多背景,我无法分辨)。这个article描述了sql注入攻击是什么以及如何防止它们。
答案 1 :(得分: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);
}