【问题标题】:Query on encrypted values using LINQ使用 LINQ 查询加密值
【发布时间】:2012-10-11 22:36:58
【问题描述】:

我有一个用户类,它的用户名需要加密保存在数据库中

public abstract class User
{
    public virtual int Id { get; protected set; }
    public virtual string Username
    {
        get
        {
            return _encryptionProvider.Decrypt(SecuredUsername);
        }
        protected set
        {
            SecuredUsername = _encryptionProvider.Encrypt(value);
        }
    }
    [Obsolete("Use the 'Username' property -- this property is only to be used by NHibernate")]
    protected virtual string SecuredUsername { get; set; }
}

我将用户实体映射如下:

public class UserMapping : ClassMap<User>
{
    public UserBaseMapping()
    {
        Id(user => user.Id).GeneratedBy.HiLo("100");
        Map(Reveal.Member<UserBase>("SecuredUsername")).Unique();
    }
}

在我不得不编写一些 LINQ 语句之前它工作得很好。

User user = _session.QueryOver<User>().Where(x => x.Username == "Hamza").SingleOrDefault();

这里的问题是,当 LINQ 将上述语句转换为 SQL 时,它会变成这样: Select * from [dbo].[User] Where Username like 'Hamza'

您可能会注意到,表中没有名为 username 的列,而是 secureusername,它包含加密的值 谁能帮我解决这个问题,我需要能够使用 LINQ 进行查询。

【问题讨论】:

标签: c# linq nhibernate fluent-nhibernate


【解决方案1】:

您可以使用自定义类型来加密您的用户名(而不是在 User 类中进行加密,而是在自定义类型中进行加密)参见http://nhforge.org/blogs/nhibernate/archive/2009/02/22/encrypting-password-or-other-strings-in-nhibernate.aspx

当您查询时,您将只能查询完全匹配,但您将能够执行如下查询:

User user = _session.QueryOver<User>()
    .Where(x => x.Username == "Hamza")
    .SingleOrDefault();

如果你想不区分大小写,你可以在自定义类型中将值转换为大写/小写。

如果您想进行 LIKE 搜索,则需要查看其他类型的索引 - 例如。 Lucene.NET 和 NHibernate.Search

【讨论】:

  • 我做到了,但同样的问题,我的问题是如何使用 LINQ 获取加密值,而不是使用 nhibernate 加密/解密数据的机制
  • 为什么需要加密值?使用 Nhibernate,数据的加密持久性对您的使用变得透明(在合理范围内),因此您不需要访问加密数据
【解决方案2】:

我没用过NHibernate,但问题是Username的定义是在模型里,不在数据库里。

基本上,您有两种选择(请记住,我从未真正使用过 NHibernate,而是使用其他实体框架/ORM),可能还有第三种选择,具体取决于 NHibernate 的 IQueryable 实现。

将整个表加载到内存中(如果它很小并且您经常执行此查询,那可能很有用,因为我猜 NHibernate 有一些智能缓存?):

User user = _session.QueryOver<User>().ToList().FirstOrDefault(x => x.Username == "Hamza");

第二个是检查@Diode 提供的加密字符串:

// Resolve string, since we are using LINQ2SQSL in some form
var encName = _encryptionProvider.Encrypt("Hamza"); 
User user = _session.QueryOver<User>().FirstOrDefault(x => x.SecuredUsername == encName);

如果您可以使用 IQueryable 的特定实例进行包装,那将是一种解决方案。查看http://msdn.microsoft.com/en-us/library/bb351562.aspx 了解 IQueryable 的描述。

但基本上,加密必须发生在服务器上,即不在数据库中,这有点限制您的选择。

编辑: 搜索所有匹配“Hamz*”的用户,我们必须加载到内存并在那里检查:

var users = _session.QueryOver<User>().ToList().Where(x => x.Username.StartsWith("Hamz"));

【讨论】:

  • 感谢您的帖子,但 Diode 解决方案的问题是,如果我想搜索字符串的一部分,假设现在让所有用户的用户名以“ham”开头,如果我使用这个那么肯定 _encryptionProvider("Ham") 与 _encryptionProvider("Hamza") 没有任何关系,因此无法搜索字符串的一部分
  • @Hamza 我添加了一个编辑,如果这是您想要的功能,您必须将表格加载到内存并在那里解密。 IE 不急于只使用 sql 访问数据库。
  • 如果我只有一个具有加密值的表,那将起作用,但我的客户需要我加密大约 5 个表中的数据并将表加载到内存并在每个请求中解密它会非常昂贵性能
  • 那么没有办法解决它,因为您的解密是应用程序层而不是持久层特定的。我建议然后重新设计应用程序,因为您无法获得当前设计所需的性能:)
【解决方案3】:

这个怎么样:

User user = _session.QueryOver<User>().Where(x => x.securedusername == _encryptionProvider("Hamza")).SingleOrDefault();

编辑: 正如我在上面的评论中提到的,您的查询存在问题。 一种选择是,(这只能在用户名唯一的情况下完成,否则可能会发生冲突) 1. 你必须想出一个对每个字符串值都是唯一的索引。 对于 EX:

SAM = xyz(110111101)
SAMI = xyzk(110111101001)

必须为数据库中的每个客户插入此索引。

然后你可以去喜欢:

`User user = _session.QueryOver<User>().Where(x => x.Index.Contains(IndexGenerator("Hamza"))).SingleOrDefault();//I do not know weather this Contains method exist in nhibernate`. But there should be. so find that :)

但是这个查询也会给出一些不必要的值,但是可以在编码中解密后使用实际用户名进一步过滤。这样才能得到准确的搜索结果。

你可以使用这个IndexGenerator 作为你的_encryptionProvider,如果它是神秘的。

【讨论】:

  • 我想到了这一点,但如果以字符串开头或结尾甚至搜索字符串的一部分,这将不起作用我也不希望 LINQ 担心加密和解密值跨度>
  • 为什么要对用户名进行加密并保存在数据库中。直观且正常的是它被加密的密码。
  • 但我不知道您的要求,这就是为什么有 2 件事 1. 用户名 2. 密码。我不希望 LINQ 担心加密和解密值。那么你将如何使用 LINQ 插入这个用户表。我仍然可以与您一起寻找答案,但是“以字符串开头或结尾甚至搜索字符串的一部分”您能否在评论中解释这句话。
  • 感谢您的回复我必须加密用户名和名字和姓氏,客户坚持这样做
  • 我的意思是,如果我想搜索字符串的一部分,假设现在让所有用户的用户名以“ham”开头,如果我使用你的方式,那么肯定 _encryptionProvider("Ham") 不会'与 _encryptionProvider("Hamza") 没有任何关系,因此无法搜索字符串的一部分
猜你喜欢
  • 1970-01-01
  • 2012-12-30
  • 1970-01-01
  • 2015-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多