Время прочтения: 4 мин.
Всем привет.
Я – технический специалист внутреннего аудита. В мои обязанности помимо всего прочего входит создание инструментов ETL. Чаще всего это консольные программы написанные на языке программирования C#, которые получают данные из различных источников (БД различных вендоров, файлы и т.д.), проводят при необходимости операции трансформации данных и загружают данные в хранилище. Так как программы активно подключаются к БД и при этом должны иметь права на запись и чтение — возникает проблема хранения данных учетных записей (логины и пароли), под которыми программа будет подключаться к БД. Навскидку находятся три решения. Рассмотрим их более подробно:
- Хранить данную критическую информацию «зашитой» в исполняемый файл exe. Из плюсов – относительная надёжность хранения, ведь для получения доступа к этой информации из вне потребуется дизассемблировать/декомпилировать исполняемый файл, из минусов — необходимость постоянно перекомпилировать исполняемый файл при смене пароля в учетных записях и опять же хранение этих данных в открытом виде в исходном коде программы, где эта информация и может быть считана посторонним наблюдателем.
- Хранить информацию в настроечных файлах приложения, но при этом само приложение должно работать на сервере приложений с ограниченным доступом. Из плюсов – легкая настройка в случае изменения данных учетных записей, из минусов – легкий доступ к критической информации всем, кто может зайти на сервер приложений.
- Хранить информацию в настроечных файлах программы в зашифрованном виде. Из плюсов – легкая настройка приложения в случае изменения данных, программа может работать не только на сервере приложений, критически важная информация хранится в виде недоступном для постороннего наблюдателя. Из минусов – только необходимость модернизации ранее написанного ПО.
По совокупности плюсов и минусов выбираем третий вариант.
Теперь чуть –чуть теории. Что же такое шифрование и для чего оно нужно? Шифрование –это трансформация для ее сокрытия от не авторизованных лиц,
но в то же время с предоставлением определенным пользователям доступа к ней. Для правильного шифрования и расшифрования данных нужна секретная информация, используемая криптографическими алгоритмами (ключ) для дешифровки.
Выделяем основные способы шифрования
- симметричное
- асимметричное
- хеширование
Симметричное шифрование это способ шифрования, в котором и для шифрования и расшифровывания используется один и тот же криптографический ключ
Асимметричное шифрование это способ при котором создаются два математически связанных ключа, один из которых передается открытым (доступных для всех) способом, а второй, приватный ключ — для расшифровывания
Где используется шифрование? Например, практически во всех популярных мессенджерах сообщения пользователей шифруются таким образом, что прочитать их могут только отправитель и адресат, большинство соединений в глобальной сети интернет сейчас используют сетевой протокол 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 можно дополнительно обфусцировать исполняемый файл программы с целью сокрытия механизма получения ключа.