Зашифрованные столбцы с Entity Framework - PullRequest
8 голосов
/ 21 июля 2010

Кто-нибудь нашел хороший способ получить зашифрованные значения из базы данных через структуру сущностей 4?

Я получил базу данных MySql с некоторыми столбцами, зашифрованными с помощью des_encrypt, и мне нужно иметь возможность получить эти значения как можно прощеи, конечно же, обновите и вставьте их.

Я думаю, это довольно странно, что в EF нет встроенной поддержки для этого.Даже наша собственная ORM-система имеет поддержку для этого.Мы просто добавляем комментарий «зашифрованный» для каждого поля, которое зашифровано, и инструмент ORM добавит в запросы des_decrypt (столбец) и des_encrypt (столбец).

Кто-нибудь?

Ответы [ 6 ]

14 голосов
/ 03 сентября 2014

Это пример реализации ответа, предложенного @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; }
        ...
    }
}

Теперь, когда бы мне ни пришлось получить User из моего 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: Как: импортировать хранимую процедуру (инструменты модели данных Entity) в 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) Каждый раз, когда вы получаете пользователяобъект, есть две поездки в базу данных вместо 1. Первая поездка для получения объекта;Вторая поездка для расшифровки SSN.Это может вызвать проблемы с производительностью, если вы не будете осторожны.

Рекомендация : НЕ расшифровывать автоматически зашифрованные поля!В моем примере, показанном выше, я расшифровал SSN, когда извлекал объект пользователя.Я сделал это только для демонстрационных целей!Спросите себя, действительно ли вам нужен SSN каждый раз, когда пользователь извлекается.Если возможно, выберите ленивое дешифрование вместо активного дешифрования!

2) Хотя я этого не демонстрировал, каждый раз, когда вы создаете / обновляете пользовательский объект, в базу данных также будут совершаться 2 поездки.Первая поездка для шифрования SSN;Вторая поездка для вставки объекта.Опять же, это может вызвать проблемы с производительностью, если вы не будете осторожны.

Рекомендация : учитывайте это снижение производительности, но не делегируйте шифрование и сохранение SSN как другой метод.Храните все это за одну операцию, иначе вы можете забыть сохранить все вместе.Таким образом, рекомендация по созданию / обновлению противоположна извлечению: выбирайте активное шифрование вместо ленивого шифрования!

2 голосов
/ 03 мая 2018

Для тех из вас, кто гуглит этот вопрос и ищет простой способ расшифровки одного столбца / строки (не всей таблицы / класса), используя симметричное шифрование и EF, вы можете сделать это одним из двух (простых) способов.

Первый путь;создайте хранимую процедуру, которая выполняет расшифровку:

CREATE PROCEDURE [dbo].[Decrypt_Credential]
@User_Name varchar(50) = NULL
AS
BEGIN
OPEN SYMMETRIC KEY My_Key_01 DECRYPTION BY CERTIFICATE MyCertName;

SELECT CONVERT(varchar, DecryptByKey(Encrypted_Password)) FROM Application_Credentials WHERE User_Name = @User_Name;

CLOSE SYMMETRIC KEY My_Key_01; 
END;

... затем вызовите эту хранимую процедуру непосредственно в коде, получив результат в виде строки:

using (var context = new YourDatabaseContext())
        {
            var result = context.Database.SqlQuery<string>("Decrypt_Credential @user", new SqlParameter("user", TheUserName)).FirstOrDefault();
        }

Второй способможет сделать это через транзакцию базы данных, которая по существу делает то же самое, что и хранимая процедура. Примечание. Я полностью осознаю, что этот пример не совместим с защитой SQL-инъекций , у меня были некоторые проблемы с параметризованными запросами, так что это был пример, с которым я работал.Если вы пойдете по этому пути, вы захотите использовать параметризованные запросы;

 using (var context = new YourDatabaseContext())
        {       
            using (var dbContextTransaction = context.Database.BeginTransaction())
            {
                try
                {
                    var sql = String.Format("OPEN SYMMETRIC KEY {0} DECRYPTION BY CERTIFICATE {1}", KeyName, CertName);
                    context.Database.ExecuteSqlCommand(sql);

                    sql = String.Format("SELECT CONVERT(varchar, DecryptByKey(Encrypted_Password)) FROM Application_Credentials WHERE User_Name = '{0}'", UserNameToDecryptCredsFor);
                    var result = context.Database.SqlQuery<string>(sql).FirstOrDefault();

                    sql = String.Format("CLOSE SYMMETRIC KEY {0}", KeyName);
                    context.Database.ExecuteSqlCommand(sql);
                }
                catch (Exception exp)
                {
                    var x = exp.ToString(); //do something with exception
                }
            }
        }
2 голосов
/ 21 марта 2017

Вы можете использовать собственную защиту шифрования своими руками, но каждый эксперт по безопасности скажет вам никогда, никогда не делайте этого .Самая сложная часть безопасности и шифрования данных - это не «AES» или какой-либо алгоритм.Это управление ключами.Рано или поздно вы столкнетесь с этим зверем, и он будет способ сложнее.

К счастью, есть инструмент под названием Crypteron CipherDb , который позаботится об этом.Фактически это выходит за рамки шифрования на основе сущностей, а также обеспечивает автоматическую защиту от несанкционированного доступа, безопасное хранение ключей, безопасное распределение ключей, перенос ключей, кэширование ключей, списки контроля доступа и многое другое.Существует бесплатная версия сообщества , и добавление в ваше приложение занимает всего несколько минут.

При интеграции с Entity Framework вы просто аннотируете модель данных с помощью [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 ИЛИ подключить API-ключ Crypteron (AppSecret) программно ( документация )

Вы можетенайти примеры приложений на GitHub можно по адресу https://github.com/crypteron/crypteron-sample-apps..

. Кстати, бесплатная версия пользуется коммерческими предложениями, поэтому в дополнение к вышесказанному вы также можете защищать потоки, файлы, объекты,очереди сообщений, базы данных NoSQL и т. д., все из одного места.

Отказ от ответственности : я работаю там, и у нас есть бесплатная версия сообщества, которую может использовать каждый (и мы не зарабатываем деньги)выкл).Если вы думаете, что это круто, скажите нам, скажите своим друзьям.Если у вас есть бюджет, получите коммерческую лицензию.Это помогает нам предлагать бесплатную версию для всех:)

2 голосов
/ 24 мая 2012

Вы можете использовать шифрование AES (двухстороннее шифрование).Когда вам нужно запросить базу данных, вы можете отправить зашифрованную строку, которая может представлять целевое значение.

Вы можете создать расширение для расшифровки сущности.

MyTableEntitiesSet.Where(c=>c.MyField == MySeekValue.Encrypt()).First().Decrypt();

Это может сделать запрос к базе данных.

Помните о размере данных, зашифрованные данные больше ...

2 голосов
/ 21 июля 2010

IMO, вы должны зашифровать перед тем, как поместить его в базу данных и сохранить как двоичные данные. Тогда вы можете легко получить byte[] с EF.

РЕДАКТИРОВАТЬ: Что делать, если вы использовали хранимую процедуру, чтобы сделать все des_encrypt и des_decrypt, а также selects/inserts/deletes для вас. Тогда EF все равно сделает для вас отображение?

0 голосов
/ 07 декабря 2012

В моем конкретном случае мне нужно было зашифровать номер кредитной карты, который всегда составляет 16 символов; поэтому я просто добавил условие в свойствах get (если длина = 16, а затем расшифровал) и в набор (если длина == 16, а затем зашифровал) свойства. Это работает и избегает меня много работы.

...