Подтвердить что ты не робот

Как сохранить безопасные переменные С++ в ОЗУ?

Я работаю над приложением С++, которое хранит некоторые секретные ключи пользователя в ОЗУ. Эти секретные ключи очень чувствительны, и я должен свести к минимуму риск любого нападения на них.
Я использую массив символов для хранения этих ключей, я прочитал некоторое содержание о хранении переменных в регистры процессора или даже кэша ЦП (т.е. Используя ключевое слово С++ register), но, похоже, нет надежного способа заставить приложение хранить некоторые из этих переменных вне RAM (я имею в виду в регистры процессора или кеш).
Может ли кто-нибудь предложить хороший способ сделать это или предложить любое другое решение для безопасного хранения этих ключей в ОЗУ (я ищу независимое от ОС решение)?

4b9b3361

Ответ 1

Ваши намерения могут быть благородными, но они также ошибочны. Короткий ответ заключается в том, что на самом деле нет способа делать то, что вы хотите, в системе общего назначения (например, товарные процессоры/материнская плата и O/S общего назначения). Даже если бы вы могли каким-то образом заставить вещи хранить только на процессоре, это все равно не помогло бы. Это будет всего лишь небольшая неприятность.

В общем случае проблема защиты памяти есть специальные решения O/S, указывающие, что память блоков не должна записываться в файл подкачки, например VirtualLock в Windows. Это стоит использовать, если вы выполняете криптографию и сохраняете конфиденциальные данные в этой памяти.

Последнее: я укажу, что меня беспокоит, что у вас есть фундаментальное непонимание ключевого слова register и его последствий для безопасности; помните, что это намек, и он не будет - действительно, он не может - заставить что-либо фактически хранить в регистре или где-либо еще.

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

Ответ 2

Вы не можете устранить риск, но можете его смягчить.

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

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

Вы можете сравнить любые два ключа, просто сравнив их маскированные версии. Вы даже можете сравнивать хеши маскированных клавиш.

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

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

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

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

@update: Я просто хотел затронуть некоторые критические замечания в комментариях ниже:

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

Некоторые люди предположили, что OP найдет способ использовать специальное оборудование с заблокированными микросхемами памяти или какой-то метод операционной системы для блокировки чипа. Это криптографически не более безопасно. В конечном счете, если у вас есть физический доступ к машине, достаточно известный хакер может использовать логический анализатор на шине памяти и восстанавливать любые данные. Кроме того, ОП заявила, что целевые системы не имеют такого специализированного оборудования.

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

Предлагаемое мной предложение имеет реальные преимущества в области безопасности. Ни одна из деталей не имеет значения, кроме маскировки ключей "xor" ключей безопасности. И есть способы сделать этот процесс немного лучше. Xor'ing клавиши ограничивают количество мест, которые программист должен учитывать как векторы атак. Как только ключи являются xord, у вас могут быть разные ключи по всей вашей программе, вы можете их скопировать, записать в файл, отправить их по сети и т.д. Ни одна из этих вещей не поставит под угрозу вашу программу, если злоумышленник не имеет буфера xor. Итак, есть ОДИНОЧНЫЙ БУФЕР, о котором вам нужно беспокоиться. Затем вы можете расслабиться вокруг каждого буфера в системе. (и вы можете mlock или VirtualLock, чтобы один буфер)

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

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

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

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

Ответ 3

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

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

Ответ 4

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

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

Ответ 5

Как говорили другие, нет безопасного способа сделать это на компьютере общего назначения. Альтернативой является использование Hardware Security Module (HSM).

Они обеспечивают:

  • большая физическая защита ключей, чем обычные ПК/серверы (защита от прямого доступа к ОЗУ);
  • большая логическая защита, поскольку они не являются общей целью - на компьютере не работает другое программное обеспечение, поэтому никакие другие процессы/пользователи не имеют доступа к ОЗУ.

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

Ответ 6

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

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

Ответ 7

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

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

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

Ответ 8

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