Комментарии 33
Имелось в виду, что перезаписывание данных на SSD — совершенно бесполезная затея, так как организация хранения данных на физическом уровне в корне отличается от таковой для HDD.
Грубо говоря, если мы хотим программно перезаписать некие данные в ячейке А, то новые данные могут попасть в ячейку Б, а ячейка А будет помечена для очистки командой TRIM и физически данные будут удалены в случайный момент времени по команде ОС или контроллера.
PS Но если через api OS прочитать «перезаписанные» сектора — то мы получим новые данные, а не старые, так что минимальный смысл тут все таки есть. Но все равно, физически старые данные на SSD не удаляются по команде «перезаписать вот эти байты»
Надо сменять парадигму. Самое простое — писать на диск шифрованный файл. Вопрос только в хранение ключей доступа. Но это уже существенно проще, чем пытаться стирать файлы (примеры, когда это не работает уже приводились — CoW ФС, SSD накопители, т.е. практически ВСЕГДА гарантированно файл удалить нельзя).
Для того чтобы проверить существует ли файл и имеет ли он корректные права можно использовать std::filesystem, которая была добавлена в C++17.
Для того, чтобы использовать std::filesystem — можно, но совершенно не нужно. Все необходимые проверки делает операционная система при открытии файла. Нельзя открыть на запись несуществующий файл или если у процесса нет прав в него писать.
Проверку на символическую ссылку тоже следует делать во время открытия файла (для этого есть специальные флажки — увы, не в std). Делать проверку до или после по пути файла — типичный пример ошибки TOCTOU.
bool kl::erase_content::overwrite_byte(const int pass, const uint8_t byte) {
...
this->file = kl::fs_util::make_open_file(file_name, "r+b");
if (!overwrite_data(pass)) {
return false;
}
return true;
}
То есть на момент проверки, файл еще не открыт
Вот я и говорю, что в этом недостаток. std::path — это просто строка с путём. Между моментом проверок и моментом собственно открытия файловая система может измениться. Представьте, что когда выполняется проверка — файл есть и это не символическая ссылка, а когда его надо открыть — туда подсунута символическая ссылка на /dev/null. Проверка в итоге бесполезна.
Да, полностью поддерживаю.
Вопросы, которые остаются:
- алгоритм шифрования. При активной работе — может влиять на быстродействие, причем значительно. Но есть же более простые алгоритмы, которые аппаратно ускорены (AES-128?)
- вопрос хранения ключей шифровки-дешифровки.
От данных в свопе ничего, наверное, не спасет.
mlock(2) спасает. Данные в памяти можно надёжно спрятать от других процессов с помощью prctl(2) (PR_SET_DUMPABLE). На других системах есть свои аналоги. Остаётся доверие ядру ОС. Ну и rowhammer, а также физический доступ к машине. Но в целом оперативная память процесса — это самое безопасное место, после какого-нибудь TPM.
Причём тут Java, если почти всё написали на C++? На Java точно так же можно свободно в файл что угодно писать, хоть через FileOutputStream, хоть через NIO file channels.
Потом подумали чтобы через JNI привязать код secure-delete. И так и сделали.
Но когда нужно было отлаживать, вот тогда стало плохо. Потому что в secure-delete очень много макросов.
Потом посмотрев на современный С++ решили реализовать на чистом С++.
this->file = kl::fs_util::make_open_file(file_name, «r+b»);Если собираемся затирать файл почему «r+b»?
Но хочется чтобы файлы были удалены без возможности востановления их в будущем.Для это следует сразу писать шифрованные файлы. И потом просто терять ключ.
https://habr.com/ru/company/wrike/blog/475854/ — 2й доклад послушайте
Затирание файлов в Java