EF中的查询可以使用ESQL语言,下面的代码接受一个字符串形式的查询条件:
public IQueryable<OpLog> GetOpLogBySql(string Sql) { return this.ObjectContext.OpLog.Where(Sql); }
其中的Sql参数可以是"it.date>'2014-1-1'"之类的字符串形式,是否有被注入的可能?
对EF的对象查询语言转T-SQL的过程不清楚,往高手赐教.
EF不是这样用的,你这样用跟回到SQL时间有什么区别了。
用EF最好就用EF的方式来写代码,where里面放的是条件表达式,用这种方式,就不会出现你说的问题了。
我也想那样写,可需要写一个通用的查询方式,因为用户的查询条件是五花八门的。总不能全部参数化?并且并不是每个参数都用到。
@slmk: 把能抽象的东西抽象出来
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; using System.Data.Entity; using System.Data.Objects; using System.Data; using IDal; using Model; using Model.QueryModel; namespace Dal { public class DalBase<T> where T : class { private DbContext db = EFContextFactory.GetCurrentDbContext(); public IDbSession _DbSession = DbSessionFactory.GetCurrenntDbSession(); public T AddEntity(T entity) { db.Entry<T>(entity).State = EntityState.Added; //下面的写法统一 db.SaveChanges(); return entity; } //实现对数据库的修改功能 public bool UpdateEntity(T entity) { db.Entry<T>(entity).State = EntityState.Modified; return db.SaveChanges() > 0; } //实现对数据库的删除功能 public bool DeleteEntity(T entity) { //EF5.0的写法 db.Set<T>().Attach(entity); db.Entry<T>(entity).State = EntityState.Deleted; return db.SaveChanges() > 0; } //实现对数据库的查询 --简单查询 public IQueryable<T> LoadEntities(Expression<Func<T, bool>> whereLambda) { //EF4.0的写法 //return db.CreateObjectSet<T>().Where<T>(whereLambda).AsQueryable(); //EF5.0的写法 return db.Set<T>().Where<T>(whereLambda).AsQueryable(); } /// <summary> /// 实现对数据的分页查询 /// </summary> /// <typeparam name="S">按照某个类进行排序</typeparam> /// <param name="pageIndex">当前第几页</param> /// <param name="pageSize">一页显示多少条数据</param> /// <param name="total">总条数</param> /// <param name="whereLambda">取得排序的条件</param> /// <param name="isAsc">如何排序,根据倒叙还是升序</param> /// <param name="orderByLambda">根据那个字段进行排序</param> /// <returns></returns> public IQueryable<T> LoadPageEntities<S>(int pageIndex, int pageSize, out int total, Expression<Func<T, bool>> whereLambda, bool isAsc, Expression<Func<T, S>> orderByLambda) { //EF4.0和上面的查询一样 //EF5.0 var temp = db.Set<T>().Where<T>(whereLambda); total = temp.Count(); //得到总的条数 //排序,获取当前页的数据 if (isAsc) { temp = temp.OrderBy<T, S>(orderByLambda) .Skip<T>(pageSize * (pageIndex - 1)) //越过多少条 .Take<T>(pageSize).AsQueryable(); //取出多少条 } else { temp = temp.OrderByDescending<T, S>(orderByLambda) .Skip<T>(pageSize * (pageIndex - 1)) //越过多少条 .Take<T>(pageSize).AsQueryable(); //取出多少条 } return temp.AsQueryable(); } public Expression<Func<T, To>> GetSortExpression<T, To>(String sortBy) { var param = Expression.Parameter(typeof(T), "x"); Expression expr = Expression.Property(param, sortBy); return Expression.Lambda<Func<T, To>>(expr, param); } public IQueryable<T> SortList(IQueryable<T> q, QueryBase pq) { var propertyType = typeof(T).GetProperty(pq.SortField).PropertyType; var sortField = pq.SortField; if (pq.Direction.ToUpper() == "ASC") { if (propertyType == typeof(bool)) { q = q.OrderBy(GetSortExpression<T, bool>(sortField)); } else if (propertyType == typeof(int)) { q = q.OrderBy(GetSortExpression<T, int>(sortField)); } else if (propertyType == typeof(int?)) { q = q.OrderBy(GetSortExpression<T, int?>(sortField)); } else if (propertyType == typeof(DateTime)) { q = q.OrderBy(GetSortExpression<T, DateTime>(sortField)); } else if (propertyType == typeof(DateTime?)) { q = q.OrderBy(GetSortExpression<T, DateTime?>(sortField)); } else { q = q.OrderBy(GetSortExpression<T, object>(sortField)); } } else { if (propertyType == typeof(bool)) { q = q.OrderByDescending(GetSortExpression<T, bool>(sortField)); } else if (propertyType == typeof(int)) { q = q.OrderByDescending(GetSortExpression<T, int>(sortField)); } else if (propertyType == typeof(int?)) { q = q.OrderByDescending(GetSortExpression<T, int?>(sortField)); } else if (propertyType == typeof(DateTime)) { q = q.OrderByDescending(GetSortExpression<T, DateTime>(sortField)); } else if (propertyType == typeof(DateTime?)) { q = q.OrderByDescending(GetSortExpression<T, DateTime?>(sortField)); } else { q = q.OrderByDescending(GetSortExpression<T, object>(sortField)); } } return q; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Model.QueryModel { public class QueryBase { public int PageIndex { get; set; } public int PageSize { get; set; } public int Total { get; set; } public string SortField { get; set; } public string Direction { get; set; } } }
上面是两个基类
下面是两个具体类
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using IDal; using Model; using Model.QueryModel; namespace Dal { public partial class DalT_Articles : DalBase<T_Articles>, IT_Articles { public IQueryable<T_Articles> LoadSearchData(ArticleQuery query) { var temp = _DbSession.DalT_Articles.LoadEntities(u => true); if (!string.IsNullOrEmpty(query.Keys)) { temp = temp.Where<T_Articles>(c => c.Title1.Contains(query.Keys)); } if (!string.IsNullOrEmpty(query.SugI)) { var i = int.Parse(query.SugI); temp = temp.Where<T_Articles>(c => c.SugI == i); } if (!string.IsNullOrEmpty(query.Sug)) { var i = int.Parse(query.Sug); temp = temp.Where<T_Articles>(c => c.Sug == i); } query.Total = temp.Count(); temp = SortList(temp, query);//实现排序 return temp.Skip(query.PageSize * (query.PageIndex - 1)).Take(query.PageSize); } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Model.QueryModel { public class ArticleQuery : QueryBase { public string Keys { get; set; } public string SugI { get; set; }//首页推荐 public string Sug { get; set; }//推荐显示 } }
你研究一下吧。
面向对象,封装、继续、多态啊!
@Alex_QY1987: 谢谢回复!Expression<Func<T, bool>>是一个不错的思路。这种表达式对象如何传递到后台呢?
可以传字符串的形式的查询条件,并不意味着你要让用户直接写"it.date>'2014-1-1'",这个字符串应该是你拼出来的,
你不检查SQL注入,那是你的问题,别怪到EF身上哦。
也就是说,ESQL有被注入的风险了?
@slmk: 当然。任何编程语言都无法和人对抗,尤其是程序员。
用参数化查询
风险是有的,建议使用参数化查询。
没有利用参数化查询,又是动态构造的sql语句,都有被注入的风险。需要靠我们(开发者)来保证的。
其实我想问的是能防止delete update insert这样的注入吗? 因为是在EF实体对象上的Where查找,会不会比传统的T-SQL更安全一些?
@slmk: 我只问你一个问题,如果你确实想要Delete的时候,EF怎么办?
你让EF如何分辨是你干的还是你干的或者是你干的好事?
@爱编程的大叔: 哥们,你看题目了吗?做过测试吗?在上面的Where里面给我注入一个delete我看看?
@slmk: 好象你对这个比较有兴趣,我就奇怪的是测试一下对你就这么难么?
园友最多只能从技术层面或是你没注意的角度帮你分析问题,如果一个简单的测试就能得出的答案,
你还来问别人测试过没有,这个似乎过了。
不同园友的答案你也看到了,都是建议参数化查询之类的。
其实就算不是参数化查询,也有简单的方法先过滤一下SQL的,保证不出现SQL注入的情况。
对于LINQ强类型编程模式,我基本可以保证95%以上的情况的不需要使用动态构造的SQL,
另外5%小心点,写个函数专门处理下不就得了。
安全问题不要交给别人。
@爱编程的大叔: 你就不敢兴趣吗?如果没有风险,干嘛费事去过滤SQL呢?我觉得这个问题大家都会遇到,所以才问的。希望有时间和已经测试过的园友可以解答一下!
@slmk: 建议用SQL SERVER Profiler监视下sql语句。
@爱编程的大叔: 大叔还是这么直白,假期结束了,总感觉缺点什么...