Время прочтения: 4 мин.

Всем привет.

Я – технический специалист внутреннего аудита. В мои обязанности помимо всего прочего входит создание инструментов ETL. Чаще всего это консольные программы написанные на языке программирования C#, которые получают данные из различных источников (БД различных вендоров, файлы и т.д.), проводят при необходимости операции трансформации данных и загружают данные в хранилище.  Так как программы активно подключаются к БД и при этом должны иметь права на запись и чтение — возникает проблема хранения данных учетных записей (логины и пароли), под которыми программа будет подключаться к БД. Навскидку находятся три решения. Рассмотрим их более подробно:

  1. Хранить данную критическую информацию «зашитой» в исполняемый файл exe. Из плюсов – относительная надёжность хранения, ведь для получения доступа к этой информации из вне потребуется дизассемблировать/декомпилировать исполняемый файл, из минусов — необходимость постоянно перекомпилировать исполняемый файл при смене пароля в учетных записях и опять же хранение этих данных в открытом виде в исходном коде программы, где эта информация и может быть считана посторонним наблюдателем.
  2. Хранить информацию в настроечных файлах приложения, но при этом само приложение должно работать на сервере приложений с ограниченным доступом. Из плюсов – легкая настройка в случае изменения данных учетных записей, из минусов – легкий доступ к критической информации всем, кто может зайти на сервер приложений.
  3. Хранить информацию в настроечных файлах программы в зашифрованном виде. Из плюсов – легкая настройка приложения в случае изменения данных, программа может работать не только на сервере приложений, критически важная информация хранится в виде недоступном для постороннего наблюдателя. Из минусов – только необходимость модернизации ранее написанного ПО.

По совокупности плюсов и минусов выбираем третий вариант.

Теперь чуть –чуть теории. Что же такое шифрование и для чего оно нужно? Шифрование –это трансформация для ее сокрытия от не авторизованных лиц,

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

Выделяем основные способы шифрования

  • симметричное
  • асимметричное
  • хеширование

Симметричное шифрование это способ шифрования, в котором и для шифрования и расшифровывания используется один и тот же криптографический ключ

Асимметричное шифрование это способ при котором создаются два математически связанных ключа, один из которых передается открытым (доступных для всех) способом, а второй, приватный ключ — для расшифровывания

Где используется шифрование? Например, практически во всех популярных мессенджерах сообщения пользователей шифруются таким образом, что прочитать их могут только отправитель и адресат, большинство соединений в глобальной сети интернет сейчас используют сетевой протокол HTTPS обеспечивающий шифрование передаваемых данных. Хеширование, несмотря на необратимость шифрования данных активно используется для проверки паролей в различных системах доступа, начиная от операционных систем и систем авторизации на различных сайтах и форумах.

После краткой разминки для мозгов вернемся к нашей проблеме. Так как данные которые мы хотели шифровать должны быть обратимы после их зашифровывания, хеширование нам не подходит. Осталось определиться между симметричным и асимметричным алгоритмами шифрования. Так как ключ никуда передаваться не должен и будет использоваться одним пользователем, то нет и смыла усложнять исходный код наших программ алгоритмами создания и проверки пар ключей, используемых при асимметричном шифровании. Соответственно выбор пал на симметричное шифрование.

В итоге мы реализовали следующую схему. В динамически подключаемой библиотеке (dll) был создан статический класс инкапсулировавший в себе весь функционал требуемый нам для шифрования/расшифровывания данных. Вот пример функции выполняющей шифрование:

 static public object Encrypt(byte[] data, string password)
        {
            SymmetricAlgorithm sa = null;
            try
            {
                sa = Rijndael.Create();
                ICryptoTransform ct = sa.CreateEncryptor(
                    (new PasswordDeriveBytes(password, null)).GetBytes(16),
                    new byte[16]);
                MemoryStream ms = new MemoryStream();
                CryptoStream cs = new CryptoStream(ms, ct, CryptoStreamMode.Write);
                cs.Write(data, 0, data.Length);
                cs.FlushFinalBlock();
                return ms.ToArray();
            }
            catch (Exception e)
            {
                return e;
            }
}
static public string Encrypt(string data, string password)
        {
            object tmp = Encrypt(Encoding.UTF8.GetBytes(data), password);
            if (!(tmp is Exception))
            {
                return Convert.ToBase64String((byte[])tmp);
            }
            else return null;
}

Теперь при создании новых программ, где требуется хранить зашифрованную информацию мы просто подключаем созданную нами dll и просто вызываем требуемые нам функции и получаем информацию для передачи в БД:

 public string UserLogin
        {
            get
            {
                object tmp = dll.Crypt.Decrypt(userLogin, getKey());
                return tmp is Exception ? "" : tmp.ToString();
            }
}
При этом, в настроечном XML файле хранится информация в следующем виде:
    <Settings>
<userLogin>p+esX621QNMR09YyY4plJQ==</userLogin>
       <userPassword>og6kLzB2woGVlnO0ZRisDA==</userPassword>
    </Settings>

Таким образом мы скрываем от постороннего наблюдателя критически важную информацию. При необходимости, учитывая достаточно слабую защищённость от дизассемблирования/декомпиляции программ, созданных на платформе .Net можно дополнительно обфусцировать исполняемый файл программы с целью сокрытия механизма получения ключа.