Как лучше всего защитить конфиденциальные данные в коде?

Я изучал способы защиты своего кода от декомпиляции.

Здесь есть несколько хороших тем, описывающих обфускацию и упаковку кода как возможные способы защиты кода. Однако ни один из них не идеален, обфускация не работает с отражением, когда используются строковые имена методов/свойств. Многие люди вообще не рекомендуют использовать обфускацию.

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

В ASP.NET есть возможность переместить конфиденциальные данные в файл .config и зашифровать его, но для этого требуется ключ сервера, т.е. связанный с одним компьютером. Я мало читал об этом, но полагаю, что нечто подобное доступно для настольных приложений. Но мне нужно, чтобы это работало на любом компьютере, на котором установлено приложение.

И вот вопрос: есть ли способы закодировать/защитить такие данные, чтобы их нельзя было прочитать вместе с декомпилированным кодом?


person net_prog    schedule 21.10.2011    source источник
comment
Проблема с тем, что вы описываете, заключается в том, что даже если вы шифруете то, что распространяете, вам нужно будет распространять ключ дешифрования вместе с ним, чтобы код мог его расшифровать. Не можете ли вы экстернализировать учетные данные и строку подключения, а затем регистрировать пользователей индивидуально (каждый получает свои собственные учетные данные)?   -  person Lucas    schedule 21.10.2011
comment
Вопрос касается лучших практик, реализующих плохую практику (вместо этого рассмотрите возможность отделения данных от логики).   -  person user4157124    schedule 19.12.2018


Ответы (7)


Первый совет: никогда не храните конфиденциальные данные непосредственно в коде. Вы всегда можете перепроектировать это, как бы искусно вы ни пытались это запутать.

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

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

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

Кроме того, шифрование отдельного файла оказывается проблемой - если вы это сделаете, тогда задействован ключ, который снова должен быть каким-то образом защищен - бесконечная рекурсия на подходе :) Защитить доступ к файлу часто бывает достаточно, но если вам действительно нужно быть как можно более безопасным, тогда решение состоит в том, чтобы использовать шифрование на основе пароля для файла. Но идея здесь не в том, чтобы хранить пароль в другом месте в системе, а в виде внеполосной информации (например, в физическом хранилище) и вводить пароль при запуске приложения. Здесь тоже есть свои проблемы: для (повторного) запуска приложения требуется физическое присутствие человека, а пароль все равно можно получить из оперативной памяти машины, на которой запущено приложение. Но это, вероятно, лучшее, что вы можете сделать без специального оборудования.

Другой хорошей альтернативой шифрованию на основе паролей может быть использование «хранилищ паролей» для конкретных ОС, таких как Windows. Изолированное хранилище — это своего рода компромисс между полным отсутствием шифрования и сохранением пароля вне диапазона.

person emboss    schedule 21.10.2011

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

Ничего конфиденциального не хранится в вашем распространяемом файле вообще...

person Paddy    schedule 21.10.2011

Я сталкивался с этой проблемой в прошлом и придумал три способа решения проблемы, но я не уверен, что какой-либо из них идеален:

  1. Запутайте или зашифруйте значение и надейтесь на лучшее. Шифрование, конечно же, является лишь дополнительным уровнем запутывания, поскольку ключ должен быть доставлен вместе с остальными.
  2. Устраните необходимость в самом ключе, используя вместо этого одностороннее шифрование. Используйте закрытый ключ для создания открытого ключа. Это можно использовать для лицензирования или проверки пароля. Вы создаете лицензии с закрытым ключом, но открытый ключ можно использовать для их проверки. Или вы используете закрытый ключ для создания пароля, который можно проверить, но нельзя отменить с помощью открытого ключа.
  3. Создайте свой собственный системный механизм генерации ключей, аналогичный тому, который используется в ASP.NET. Вы можете ограничить эффект от того, что кто-то отменит шифрование/обфускацию на шаге 1, создав уникальный ключ для каждой установки или сайта.
person BlueMonkMN    schedule 21.10.2011
comment
Пункты №2 и №3 кажутся интересными. Я пытаюсь представить № 2, есть ли дополнительная информация об этом методе? - person net_prog; 21.10.2011
comment
См. stackoverflow.com /вопросы/2742583/ - person BlueMonkMN; 21.10.2011
comment
Моя предыдущая ссылка приводит к вопросу, когда действительно мой ответ является соответствующей частью: stackoverflow.com/a/2744914/78162 - person BlueMonkMN; 22.02.2016
comment
Вы можете сохранить ключ в Hardware, здесь я говорю об аппаратных модулях безопасности. Подробнее читайте здесь: [markgamache.blogspot. в/2011/05/ - person iamjayp; 10.07.2017

Существует множество методов, но реальность такова, что если вы действительно хотите защитить свой код, единственным решением является использование «профессиональных» продуктов :-) не пытайтесь изобретать велосипед. Эти продукты обычно имеют опции для шифрования строк. Настоящая проблема в другом: без профессионального продукта (и даже С профессиональным продуктом) эксперт может просто поставить точку останова и посмотреть параметры, переданные библиотечному методу (например тот, который открывает соединения). Теперь... Если вы действительно хотите зашифровать строки своего кода, это довольно просто. Но будет ли это полезно? Нет.

Теперь, чтобы никто не пометил это как «не ответ», я опубликую простой код шифрования/дешифрования:

// Generate key. You do it once and save the key in the code
var encryptorForGenerateKey = Aes.Create();
encryptorForGenerateKey.BlockSize = 128;
encryptorForGenerateKey.KeySize = 128;
encryptorForGenerateKey.GenerateKey();
encryptorForGenerateKey.GenerateIV();

var key = encryptorForGenerateKey.Key;
var iv = encryptorForGenerateKey.IV;

// Encrypt: this code doesn't need to be in the program. You create a console
// program to do it
var encryptor = Aes.Create();
var encryptorTransformer = encryptorForGenerateKey.CreateEncryptor(key, iv);

string str = "Hello world";
var bytes = Encoding.UTF8.GetBytes(str);
var encrypted = encryptorTransformer.TransformFinalBlock(bytes, 0, bytes.Length);
var encryptedString = Convert.ToBase64String(encrypted);

Console.WriteLine(encryptedString);

// Decrypt: this code needs to be in the program

var decryptor = Aes.Create();
var decryptorTransformer = decryptor.CreateDecryptor(key, iv);

byte[] encrypted2 = Convert.FromBase64String(encryptedString)

var result = decryptorTransformer.TransformFinalBlock(encrypted2, 0, encrypted2.Length);

var str2 = Encoding.UTF8.GetString(result);

Этот код явно небезопасен. Любой может декомпилировать программу, добавить Console.WriteLine(str2) и перекомпилировать ее.

person xanatos    schedule 21.10.2011
comment
То, что вы пишете, это шифрование строк вне программы и сохранение зашифрованных строк в виде const string внутри программы вместе с ключом шифрования. Затем программа также содержит код расшифровки. Таким образом, если я пойду и декомпилирую программу с помощью .NET Reflector, я увижу ключ и логику дешифрования, т.е. бесполезную. Это правильно? - person net_prog; 21.10.2011
comment
@net_prog Я думал, что комментария, выделенного жирным шрифтом в конце ответа, было достаточно :-) Да, вы правы. Разница между моим кодом и кодом, сгенерированным профессиональным обфускатором, заключается в том, что код обфускатора гораздо сложнее расшифровать, чтобы найти строки. - person xanatos; 21.10.2011
comment
@net_prog Дело в том, что если ваш босс попросил шифрование строк, теперь вы можете дать ему шифрование строк. Еще один флажок установлен. Если вам действительно нужно решение... Что ж... Его нет. Если вы дадите ключ, код расшифровки и строку человеку, у него будет все, что ему нужно для расшифровки. - person xanatos; 21.10.2011

Конечно, вы можете зашифровать свою строку перед ее компиляцией, но ваш код иногда нуждается в этом в виде простого текста, если вы используете простой URL-адрес db или http.

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

Например, вы можете поместить dll COM или C++ для хранения зашифрованных строк. Неуправляемая dll не подлежит декомпиляции, однако опытные люди, конечно, могут понять дизассемблирование dll. И, как было сказано ранее, когда-нибудь вам понадобятся простые данные, и в этот момент нет надежной защиты.

Единственное, что вы можете сделать, это изменить архитектуру.

Например, если ваша база данных находится в сети, а ваше приложение является клиентским, вы можете подключиться с помощью веб-сервисов. Затем вы можете предоставлять только те веб-сервисы, которые действительно нужны пользователю, нет риска, что пользователь будет писать sql-запросы. Затем вы можете добавить логику защиты на сервер, а не на клиент.

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

person Salvatore Previti    schedule 21.10.2011

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

Что касается хранения учетных данных, я обычно всегда храню их в файле конфигурации приложения. Если мне нужно защитить его, я использую SecureString и некоторое шифрование. И это может работать для любой информации о конфигурации, а не только для учетных данных. Здесь есть действительно хорошая статья о защите файлов конфигурации: Шифрование паролей в файле .NET app.config

person Ucodia    schedule 21.10.2011

Возможно, вам следует прочитать больше о шифровании файла web.config http://learn.iis.net/page.aspx/141/using-encryption-to-protect-passwords/

В противном случае вы мало что можете сделать. Хранение конфиденциальных данных в коде не вариант, поскольку любой, у кого есть инструмент Reflector, может открыть его и увидеть. Если вы хотите, чтобы код или переменные были невидимы для всех, вы должны создать веб-сервис на частном сервере, который принимает данные, преобразует их с помощью своей магии и возвращает их клиенту. Таким образом, все, что происходит между публикацией и получением данных, сохраняется в секрете.

person Erwin    schedule 21.10.2011
comment
accepts data, transforms it through it's magic and returns it to the client не является решением. Сетевой трафик может быть перехвачен или с помощью некоторых дизассемблеров может быть присоединен работающий код. - person L.B; 21.10.2011