Безопасность PasswordVault при использовании в приложении Desktop
Я хотел бы использовать Windows.Security.Credentials.PasswordVault в своем настольном приложении (на основе WPF) для безопасного хранения пароля пользователя. Мне удалось получить доступ к этому API Windows 10, используя эту статью Desktop Bridge и, таким образом, с идентификатором пакета не устраняет эту уязвимость.
Любые идеи по исправлению и сохранению данных приложений из других приложений?
ОБНОВЛЕНИЕ:. Похоже, что PasswordVault не добавляет дополнительной защиты над DPAPI. Случай закрыт отрицательным результатом.
Ответы
Ответ 1
(это от того, что я могу понять из вашего сообщения)
Нет реального способа предотвращения доступа к данным между настольными приложениями при использовании такого API http://www.hanselman.com/blog/SavingAndRetrievingBrowserAndOtherPasswords.aspx. Вероятно, вы просто захотите расшифровать свою информацию.
ограничение доступа к памяти затруднено, код, выполняемый пользователем, всегда извлекается пользователем, поэтому было бы трудно ограничить это.
Вы рассмотрели использование API защиты данных Windows:
https://msdn.microsoft.com/en-us/library/ms995355.aspx
схватил прямо из источника
DPAPI - это простой в использовании сервис, который принесет пользу разработчикам, которые должны обеспечить защиту конфиденциальных данных приложений, таких как пароли и закрытые ключи
WDPAPI использует ключи, сгенерированные операционной системой, и Triple DES для шифрования/дешифрования ваших данных. Это означает, что ваше приложение не должно генерировать эти ключи, что всегда приятно.
Вы также можете использовать класс Rfc2898DeriveBytes, это использует генератор псевдослучайных чисел для дешифрования вашего пароля. Это безопаснее, чем большинство расшифровщиков, так как нет практического способа вернуться от результата обратно к паролю. Это действительно полезно для проверки пароля ввода и не возврата его обратно. Я никогда не использовал это сам, поэтому я не смог бы помочь вам.
https://msdn.microsoft.com/en-us/library/system.security.cryptography.rfc2898derivebytes(v=vs.110).aspx
см. также этот пост, который дает мне лучшее объяснение, чем я могу.
Как безопасно сохранить имя пользователя/пароль (локально)?
Если я неправильно понял вопрос, скажите мне, я попытаюсь обновить ответ.
ЗАМЕЧАНИЕ, что современные приложения/метро не имеют этой проблемы, хотя они все еще доступны другими способами.
Ответ 2
Жесткая правда заключается в том, что сохранение пароля в настольном приложении на 100% безопасно просто невозможно. Однако вы можете приблизиться к 100%.
Что касается вашего оригинального подхода, в PasswordVault используется Служба блокировки учетных данных, которая встроена в окна для безопасного хранения данных, Учетная запись привязана к профилю пользователя. Поэтому сохранение ваших данных через PasswordVault по существу эквивалентно подходу master password для защиты данных, о котором я подробно расскажу ниже. Единственное отличие состоит в том, что главный пароль в этом случае является учетными данными пользователя. Это позволяет приложениям, запущенным во время сеанса пользователя, получать доступ к данным.
Примечание.. Чтобы быть ясным, я строго говорю об их хранении таким образом, чтобы вы могли получить доступ к простому тексту. То есть, хранить его в зашифрованной базе данных любого типа или шифровать его самостоятельно и где-то хранить зашифрованный текст. Такая функциональность необходима в таких программах, как диспетчеры паролей, но не в программах, для которых требуется только некоторая аутентификация. Если это не необходимость, я настоятельно рекомендую хешировать пароль, в идеале согласно инструкциям, изложенным в этом ответьте zaph. (Более подробная информация в этом отличный пост Томас Порнин).
Если это необходимо, все становится немного сложнее: если вы хотите, чтобы другие программы (или пользователи, которые, как я полагаю), не могли просматривать пароль открытого текста, тогда ваш единственный реальный вариант - зашифровать его. Хранение зашифрованного текста в PasswordVault является необязательным, поскольку, если вы используете хорошее шифрование, единственным слабым местом является обнаружение вашего ключа. Поэтому сам зашифрованный текст можно хранить в любом месте. Это подводит нас к самому ключу.
В зависимости от того, сколько паролей вы пытаетесь сохранить для каждого экземпляра программы, вам, возможно, не придется беспокоиться о создании и безопасном хранении ключа вообще. Если вы хотите хранить несколько паролей, вы можете просто попросить пользователя ввести один мастер-пароль, выполнить некоторые соления и хэширования и использовать результат в качестве ключа шифрования для всех других паролей. Когда пришло время для расшифровки, попросите пользователя снова ввести его. Если вы храните несколько паролей, я настоятельно призываю вас пойти с этим подходом. возможен самый безопасный подход. Тем не менее, для остальной части моего сообщения я буду придерживаться предположения, что это не жизнеспособный вариант.
Прежде всего, я призываю вас не иметь один и тот же ключ для каждой установки. Создайте новый для каждого экземпляра вашей программы на основе надежных генерируемых случайных данных. Сопротивляйтесь соблазну "избегать хранения ключа", создавая его на лету каждый раз, когда это необходимо, на основе информации о системе. Это безопасно, как hardcoding string superSecretKey = "12345";
в вашей программе. Это не потребует от злоумышленников выяснить процесс.
Теперь его хранение является реальной сложной частью. Общее правило infosec следующее:
Ничего не безопасно после физического доступа
Так, в идеале, никто не будет. Хранение ключей шифрования на правильно защищенном удаленном сервере минимизирует вероятность его восстановления злоумышленниками. Были написаны целые книги о безопасности на стороне сервера, поэтому я не буду обсуждать это здесь.
Еще один хороший вариант - использовать HSM (Hardware Security Module). Эти элегантные маленькие устройства построены для работы. Доступ к ключам, хранящимся в HSM, практически невозможно. Однако этот вариант является жизнеспособным, если вы точно знаете, что каждый пользовательский компьютер имеет один из них, например, в корпоративной среде.
.Net предоставляет решение своего рода через систему конфигурации. Вы можете сохранить свой ключ в зашифрованном разделе вашего app.config
. Это часто используется для защиты строк подключения. Есть много ресурсов на то, как это сделать. Я рекомендую этот сказочный пост в блоге, который расскажет вам больше всего о том, что вам нужно знать.
Причина, по которой я сказал ранее, не идти просто с созданием ключа на лету, состоит в том, что, как и сохранение его как переменной в вашем коде, вы полагаетесь исключительно на обфускацию, чтобы сохранить ее в безопасности. Дело в том, что это обычно не так. Однако иногда у вас нет другого выбора. Введите криптографию белого ящика.
Криптография белого ящика - это, по сути, обфускация до крайности. Он должен быть эффективным даже в сценарии с белым ящиком, где злоумышленник имеет доступ и может изменять байт-код. Это воплощение безопасности через неясность. В отличие от простого постоянного скрытия (infosec говорит за подход string superSecretKey
) или генерирования ключа, когда это необходимо, криптография белого ящика в основном полагается на генерацию самого шифра на лету.
Целый papers был написан на нем. Трудно снять правильную реализацию, и ваш пробег может отличаться. Вы должны только учитывать это, если действительно действительно действительно хотите сделать это как можно безопаснее.
Обфускация, однако, все еще запутывает. Все, что может действительно сделать, это медленные атаки нападающих. Окончательное решение, которое я могу предложить, может показаться обратным, но оно работает: не скрывайте ключ шифрования в цифровом виде. Скрыть его физически. Попросите пользователя вставить USB-накопитель, когда пришло время для шифрования (безопасно) создать случайный ключ, а затем записать его на USB-накопитель. Затем, всякий раз, когда настало время для дешифрования, пользователю остается только вернуть диск, и ваша программа считывает этот ключ.
Это немного похоже на подход с основным паролем, поскольку он оставляет его пользователю, чтобы держать ключ в безопасности. Однако он имеет некоторые заметные преимущества. Например, этот подход позволяет использовать массивный ключ шифрования. Ключ, который может вместить только один мегабайтный файл, может занять буквально миллиарды лет, чтобы прорваться через грубую силовую атаку. Кроме того, если ключ когда-либо обнаруживается, пользователь сам виноват.
В заключение, см., если вы можете избежать необходимости хранить ключ шифрования. Если вы не можете, не храните его локально любой ценой. В противном случае, ваш единственный вариант - сделать так, чтобы хакеры могли понять это как можно скорее. Независимо от того, как вы это сделаете, убедитесь, что каждый ключ отличается, поэтому, даже если злоумышленники его найдут, ключи других пользователей будут безопасными.
Ответ 3
Альтернативой может быть шифрование пароля с помощью собственного личного ключа, хранящегося где-то в вашем коде. (Кто-то может легко разобрать ваш код и получить ключ), а затем сохранить зашифрованный пароль в PasswordVault, однако единственная ваша безопасность - любое приложение не будет иметь доступа к паролю.
Это двойная безопасность, в случае взломанных компьютеров злоумышленник может получить доступ к PasswordVault, но не ваш пароль, поскольку для дешифрования пароля им потребуется еще один закрытый ключ, который будет скрыт где-то в вашем коде.
Чтобы сделать его более безопасным, если вы оставите свой секретный ключ на своем сервере и предоставите API для шифрования и дешифрования пароля перед хранением в хранилище, он сделает его наиболее безопасным. Я думаю, что это причина, по которой люди перешли к OAuth (сохраняя токен OAuth в PasswordVault) и т.д., А не сохраняя пароль в хранилище.
В идеале я бы рекомендовал не хранить пароль, а вместо этого получить некоторый токен с сервера и сохранить его и использовать этот токен для аутентификации. И сохраните этот токен в PasswordVault.
Ответ 4
Всегда можно нажать защиту, используя различные стратегии шифрования и хранения. Сделать что-то сложнее - это сделать поиск данных более длинным, никогда невозможным. Следовательно, вам необходимо рассмотреть наиболее подходящий уровень защиты, учитывая стоимость исполнения x времени (человеческий и машинный) и стоимость разработки x временные аспекты.
Если я строго рассмотрю ваш запрос, я бы просто добавил слой (класс, интерфейс) для шифрования ваших паролей. Лучше всего использовать асимметричное шифрование (а не RSA). Предположим, что другие программы не имеют доступа к вашим программным данным (программе, файлам или процессу), этого достаточно. Вы можете использовать SSH.NET(https://github.com/sshnet/SSH.NET), чтобы достичь этого быстро.
Если вы хотите повысить безопасность и обеспечить определенный уровень защиты от двоичного обратного проектирования (включая поиск частного ключа), я рекомендую небольшую (ограниченную технологией) зашифрованную виртуальную машину (например, Docker, https://blogs.msdn.microsoft.com/mvpawardprogram/2015/12/15/getting-started-with-net-and-docker/), например Denuvo (https://www.denuvo.com/). Шифрование уникально для каждого клиента и машины. Вам нужно инкапсулировать программу С# в программу c/С++ (которая действует как контейнер), которая будет делать все шифрование в расширении памяти.
Вы можете реализовать свою собственную стратегию в зависимости от типа инвестиций и требуемой гарантии.
В случае, если ваша программа является бэкэнд-программой, вы можете выбрать лучшую стратегию (только я действительно рекомендую) всего, что должно хранить закрытый ключ на стороне клиента, открытый ключ на стороне сервера и иметь локальную расшифровку, все Таким образом, передаваемый пароль будет зашифрован. Я хотел бы отметить, что пароль и ключи на самом деле являются разными стратегиями для достижения одной и той же цели: проверка, говорит ли программа правильному человеку, не зная личности человека; Я имею в виду это: вместо хранения паролей лучше хранить непосредственно открытые ключи.