Явное удаление конфиденциальных данных из памяти?

Недавняя утечка из Wikileaks имеет ЦРУ, делая следующее:

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

НЕ СООТВЕТСТВУЙТЕ НА ЭКСПЛУАТАЦИОННУЮ СИСТЕМУ, ЧТОБЫ ДЕЛАТЬ ДАННОЕ ПРЕКРАЩЕНИЕ ИСПОЛНЕНИЕ.

Я являюсь разработчиком в мире * nix; Я рассматриваю это как просто изменение значения переменной (обеспечение того, что я не передаю значение, а вместо ссылки); поэтому, если строка содержит 100 символов; пишут 0, то есть 101 символ. Это действительно так просто? Если нет, то почему и что следует делать вместо этого?

Примечание. Есть аналогичный вопрос, который задал этот вопрос; но это в мире С# и Windows. Таким образом, я не рассматриваю этот вопрос как дубликат.

Ответ 1

Я являюсь разработчиком в мире * nix; Я вижу это просто изменение значения переменной (обеспечение того, что я не перехожу по значению; вместо ссылки); поэтому, если строка содержит 100 символов; пишут 0, то есть 101 символ. Это действительно так просто? Если не, почему и что следует делать вместо этого?

Это должно быть так просто. Дьявол находится в деталях.

  • Функции распределения памяти, такие как realloc, не гарантируют оставить память в одиночку (вы не должны полагаться на их выполнение так или иначе - см. также этот вопрос). Если вы выделите 1 КБ памяти, то перераспределите его до 10 К, ваш оригинал К может все еще находиться где-то в другом месте, содержащий его чувствительную полезную нагрузку. Затем он может быть выделен другой нечувствительной переменной или буфером или нет, и через новую переменную можно было бы получить доступ к части или ко всему старому контенту, как это было в случае нехватки места в некоторых файловых системах.
  • ручное обнуление памяти (и, с большинством компиляторов, bzero и memset считать как ручные петли), может быть оптимизировано, особенно если вы обнуляете локальную переменную ( "ошибка" - фактически функция, с обходным решением).
  • некоторые функции могут оставлять "следы" в локальных буферах или в памяти, которые они выделяют и освобождают.
  • на некоторых языках и в каркасах целые части данных могут быть перемещены (например, во время так называемой "сборки мусора", как это заметил @gene). Вы можете сказать GC не обрабатывать вашу чувствительную область или иначе "приколоть" ее к этому эффекту, и если да, то это должно сделать. В противном случае данные могут заканчиваться несколькими копиями.
  • информация, возможно, прошла и оставила следы, о которых вы не знаете (тривиальный пример: пароль, отправленный через сеть, может задерживаться в буфере чтения сетевой библиотеки).
  • живая память может быть заменена на диск.

Пример realloc делает свою вещь. Память частично переписывается, и с некоторыми библиотеками это будет "работать" только в том случае, если "a" не является единственной выделенной областью (поэтому вам также нужно объявить c и выделить что-то сразу после a, так что a не является последним объектом и остается свободно расти):

int main() {
        char *a;
        char *b;
        a = malloc(1024);
        strcpy(a, "Hello");
        strcpy(a + 200, "world");
        printf("a at %08ld is %s...%s\n", a, a, a + 200);
        b = realloc(a, 10240);
        strcpy(b, "Hey!");
        printf("a at %08ld is %s...%s, b at %08ld is %s\n", a, a, a + 200, b, b);
        return 0;
}

Вывод:

 a at 19828752 is Hello...world
 a at 19828752 is 8????...world, b at 19830832 is Hey!

Итак, память на адресе a была частично переписана - "Привет" потеряно, "мир" все еще существует (а также при b + 200).

Таким образом, вам необходимо самостоятельно обрабатывать перераспределения чувствительных областей; еще лучше, предварительно распределите все это при запуске программы. Затем сообщите ОС, что чувствительная область памяти никогда не будет заменена на диск. Затем вам нужно обнулить его таким образом, чтобы компилятор не мог вмешиваться. И вам нужно использовать достаточно низкоуровневый язык, который, вы уверен, сам не делает: простая конкатенация строк может появляться две или три копии данных - я уверен, что это произошло в PHP 5.2.

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

И тогда вам нужно обеспечить работу с отказами - например, что произойдет, если программа прерывается? Может ли это быть прервано намеренно?

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

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

Ответ 2

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

Например, компиляторы С++ могут оптимизировать вызовы memset, если он определяет, что данные не читаются после записи. Или операционные системы, возможно, вытащили память на диск, потенциально оставляя данные доступными таким образом.