有人想通过实体框架4从数据库中提取加密值的好方法?使用实体框架加密的列
我得到了一个MySql数据库,其中有一些使用des_encrypt加密的列,并且需要能够尽可能简单地获取这些值,当然,还需要更新并插入它们。
我认为这很奇怪,似乎没有在EF中为此构建的支持。即使我们自己构建的ORM系统也支持这一点。我们只是为加密的每个字段添加一个“加密”注释,并且ORM工具将在查询中添加des_decrypt(column)和des_encrypt(column)。
有人吗?
有人想通过实体框架4从数据库中提取加密值的好方法?使用实体框架加密的列
我得到了一个MySql数据库,其中有一些使用des_encrypt加密的列,并且需要能够尽可能简单地获取这些值,当然,还需要更新并插入它们。
我认为这很奇怪,似乎没有在EF中为此构建的支持。即使我们自己构建的ORM系统也支持这一点。我们只是为加密的每个字段添加一个“加密”注释,并且ORM工具将在查询中添加des_decrypt(column)和des_encrypt(column)。
有人吗?
国际海事组织你应该加密之前把它放入数据库并将其存储为二进制数据。然后你可以很容易地用EF获得byte[]
。
编辑:如果您使用存储过程为您执行所有des_encrypt
和des_decrypt
以及selects/inserts/deletes
怎么办。那么EF仍然会为你做映射吗?
您可以使用AES加密(2路加密)。当您需要查询数据库时,您可以发送可以表示目标值的加密字符串。
您可以创建一个扩展来解密该实体。
MyTableEntitiesSet.Where(c=>c.MyField == MySeekValue.Encrypt()).First().Decrypt();
这可以做一个数据库查询。
要注意数据的大小,加密的数据是大...
旧的问题和答案,但请注意,如果您尝试这样做,它将只会在您使用固定的初始向量时才起作用,因为它不会推荐潜在地允许攻击者了解数据。应该使用每个加密的随机IV,这意味着每次加密某个东西时都会得到不同的值。 – 2013-04-19 16:34:02
在我的特定情况下,我需要加密的信用卡号码,这始终是16个字符;所以我只是在get(如果lenght!= 16然后解密)和set(如果长度为16,然后加密)属性中添加了一个条件。它的工作,并避免了我很多工作。
这是@TheCloudlessSky提出的答案的实现示例。我认为这会帮助那些想知道如何去实施它的人。
我正在使用现有的数据库,所以基本模型类是为我自动生成的。
自动生成User.cs:
namespace MyApp.Model
{
public partial class User
{
public int UserId { get; set; }
public byte[] SSN { get; set; }
...
}
}
我创建了自己User.cs. (注意它与自动生成的User.cs位于同一个命名空间中,并且没有编译器错误,因为自动生成的User.cs被声明为部分类!另外,我自己的User.cs不能与自动生成User.cs因为文件名冲突!)
namespace MyApp.Model
{
public partial class User
{
public string DecryptedSSN { get; set; }
...
}
}
现在,每当我是从我的DbContext检索用户,我会看到自动生成的类以及在中定义的定义的所有属性我的增强类。
这是我的UserRepository的实现。CS:
namespace MyApp.Model
{
public interface IUserRepository
{
User Get(int userId);
...
}
public class UserRepository : IUserRepository
{
public User GetById(int userId)
{
using (var dataContext = MyDbContext())
{
var user = dataContext.Users.Find(u => u.UserId == userId);
var decryptedSSNResult = dataContext.Decrypt(u.SSN);
user.DecryptedSSN = decryptedSSNResult.FirstOrDefault();
return user;
}
}
}
}
现在你可能想知道如何/在哪里我MyDbContext.Decrypt()从获得?
这不是自动生成的。但是,您可以将此存储过程导入到自动生成的Model.Context.cs文件中。 (这个过程在官方的EntityFramework文章中有很好的记录:如何导入一个存储过程(实体数据模型工具)http://msdn.microsoft.com/en-us/library/vstudio/bb896231(v=vs.100).aspx)
为防万一你不知道结果应该是什么样子,是什么在我的Model.Context.cs自动生成:
namespace MyApp.Model
{
// using statements found here
public partial class MyDbContext : DbContext
{
public MyDbContext()
: base("name = MyDbContext")
{ }
public virtual ObjectResult<string> Decrypt(byte[] encryptedData)
{
var encryptedDataParameter = encryptedData != null ?
new ObjectParameter("encryptedData", encryptedData) :
new ObjectParameter("encryptedData", typeof(byte[]));
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<string>("Decrypt", encryptedDataParameter);
}
// similar function for Encrypt
}
}
这是我的解密存储过程的样子:
CREATE PROCEDURE decrypt
@encryptedData VARBINARY(8000)
AS
BEGIN
OPEN SYMMETRIC KEY xxx_Key DECRYPTION BY CERTIFICATE xxx_Cert;
SELECT CAST(DECRYPTIONBYKEY(@encryptedData) AS NVARCHAR(MAX)) AS data;
CLOSE ALL SYMMETRIC KEYS;
END;
GO
性能注意事项
既然我已经向您展示了@TheCloudlessSky给出的答案的实现,我想快速地突出显示一些与性能相关的要点。
1)每次检索一个用户对象时,都会有2次到达数据库而不是1次。第一次检索对象;第二次解密SSN。如果您不小心,这可能会导致性能问题。
推荐:不要自动解密加密字段!在我上面显示的例子中,当我检索用户对象时,我解密了SSN。我这样做只是为了演示目的!问问你自己是否真的需要SSN每次检索用户。如果可能的话,选择通过渴望解密的延迟解密!
2)虽然我没有证明这一点,但是每次创建/更新用户对象时,还会有2次到数据库的行程。第一次加密SSN;第二次插入对象。如果您不小心,这又会导致性能问题。
建议:请注意这种性能下降,但不要委派加密和保存SSN作为不同的方法。把它全部保存在一个操作中,否则你可能忘记完全保存它。因此,创建/更新的建议与检索相反:选择通过懒加密的急切加密!
我给你一个努力票。但我不同意你的方法。我不希望我的数据库解密值。我可以将所有这些信息存储在我的应用程序中,而不必两次前往数据库。 – mac10688 2015-03-27 13:26:01
@ mac10688我同意你关于多次访问数据库的性能问题。通常,为CUD操作编写专用存储过程并通过实体框架将它们链接到模型比存储过程(如加密/解密)更有效。但我想演示一种使用由数据库而不是应用程序管理的密钥来实现加密/解密的方法。 – 2015-03-31 03:38:49
如果有人对如何实现这一点感到好奇,我提供了一个链接,指向实体框架如何将CUD存储过程连接到CUD操作:https://msdn.microsoft.com/en-us/data/jj593489。我知道链接通常是不受欢迎的,但是由于这个链接是MSDN实体框架文档站点,所以我希望人们不会介意。 – 2015-03-31 03:44:28
你可以去DIY /卷 - 自己的加密安全,但每个安全专家会告诉你never, ever, do that。数据安全和加密中最难的部分实际上不是“AES”或某种算法。这是关键管理。迟早,你会面对这个野兽,它的方式更难。
幸运的是,有一个名为Crypteron CipherDb的工具可以解决这个问题。事实上,它超越了实体框架加密,还提供了自动防篡改保护,安全密钥存储,安全密钥分配,密钥延伸,密钥缓存,访问控制列表等等。有一个免费社区版,它只需要几分钟时间添加到您的应用程序。
当与实体框架集成,你只是注释数据模型[Secure]
或名称的属性,以类似Secure_SocialSecurityNumber
(该Secure_
是关键部分)和CipherDb负责剩下的照顾。
例如,你的数据模型是:
public class Patient
{
public int Id {get; set;}
[Secure]
public string FullName {get; set;}
[Secure]
public string SocialSecurityNumber {get; set;}
}
而且你的web.config将
<configuration>
<configSections>
<section
name="crypteronConfig"
type="Crypteron.CrypteronConfig, CipherCore, Version=2017, Culture=neutral, PublicKeyToken=e0287981ec67bb47"
requirePermission="false" />
</configSections>
<crypteronConfig>
<myCrypteronAccount appSecret="Get_this_from_http://my.crypteron.com" />
</crypteronConfig>
</configuration>
它的建议,以确保你的web.config,或者将Crypteron API密钥(AppSecret )以编程方式(documentation)
您可以在GitHub上找到示例应用程序https://github.com/crypteron/crypteron-sample-apps。 。
顺便说一下,免费版可以从商业产品中受益,因此除了上述之外,您还可以在一个地方保护流,文件,对象,消息队列,NoSQL数据库等。
免责声明:我在那里工作,我们有一个免费的社区版,任何人都可以使用(而且我们不赚任何钱)。如果你认为这很酷,告诉我们,告诉你的朋友。如果您有预算,请获得商业许可。它可以帮助我们向所有人提供免费版:)
看起来像一个很好的解决方案,如果我创建了一个新的数据库,我可能会这样做。 问题是,数据库非常大,被大量的项目所使用,因此查看代码并改变它将是一项巨大的工作。 – Andreas 2010-07-22 06:53:10
@Andreas - 查看我上面的修改。 – TheCloudlessSky 2010-07-22 12:02:59
感谢您的建议。 这看起来像一个非常好的主意,我试了一下。 不幸的是,如果我希望能够对表中的所有解密数据执行LINQ查询,则必须先执行存储过程。这是永久的,因为它是250,000行,每行5列需要解密。 这样做:context.AllMembers()。其中(x => x.MemberId == 1)将花费太长时间。 当然我可以做一个采用memberid参数的SP,但是如果我想在例如与LINQ的名字? 也许我错过了一些重要的东西在这里... – Andreas 2010-07-23 08:46:29