Как стать автором
Поиск
Написать публикацию
Обновить

Комментарии 33

Заголовок вводит в заблуждение. Если сопоставить его с содержанием статьи, может создаться впечатление, что и в общем случае мы обычно удаляем файлы некорректно.
Совершенно согласен. Речь тут совсем не про «корректность», как ее обычно понимают.
Согласен, лучше переименовать «Затирание файлов в Java»
Совсем не уверен, что в случае SSD контроллер действительно будет записывать байты физически в те же ячейки при многократной перезаписи, а в таком случае затея теряет смысл.
Приложения писалося для ПК, и для удаления/затирания подошло очень хорошо. Если есть какие-то замечания по коду, буду очень рад замечанием. Можете писать issues на github.
code
SSD может стоять как в ПК, так и в лептопах.
Имелось в виду, что перезаписывание данных на SSD — совершенно бесполезная затея, так как организация хранения данных на физическом уровне в корне отличается от таковой для HDD.
Грубо говоря, если мы хотим программно перезаписать некие данные в ячейке А, то новые данные могут попасть в ячейку Б, а ячейка А будет помечена для очистки командой TRIM и физически данные будут удалены в случайный момент времени по команде ОС или контроллера.

PS Но если через api OS прочитать «перезаписанные» сектора — то мы получим новые данные, а не старые, так что минимальный смысл тут все таки есть. Но все равно, физически старые данные на SSD не удаляются по команде «перезаписать вот эти байты»
Все это прекрасно, но — увы — бессмысленно. Нет никакой гарантии, что при затирании файла вы затираете именно старые данные на диске. К примеру, если файловая система поддерживает версионность или CoW, то вы будете старательно каждый из 35 раз писать в новое место.
Можно проверить той же Recuva, до и после затирания файлов в директории.
В процессе работы вашей программы операционная система делает снапшот файловой системы, или lvm snapshot. Все, ваша куча методов затирания бессмысленна.
Все эти утилиты «секьюрного удаление по военным алгоритмам» — это вообще такой фан-сервис для домашних параноиков. Гарантию может обеспечить только затирание накопителя целиком.
Вы не будете каждый час или каждый день затирать весь диск.
Если мне нужна безопасность, а не её иллюзия — да, придётся.

Надо сменять парадигму. Самое простое — писать на диск шифрованный файл. Вопрос только в хранение ключей доступа. Но это уже существенно проще, чем пытаться стирать файлы (примеры, когда это не работает уже приводились — CoW ФС, SSD накопители, т.е. практически ВСЕГДА гарантированно файл удалить нельзя).

Для того чтобы проверить существует ли файл и имеет ли он корректные права можно использовать std::filesystem, которая была добавлена в C++17.

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


Проверку на символическую ссылку тоже следует делать во время открытия файла (для этого есть специальные флажки — увы, не в std). Делать проверку до или после по пути файла — типичный пример ошибки TOCTOU.

Для проверки в fs::exists(std::path), нужен объект std::path. То есть на момент проверки, файл еще не открыт (например через fopen()), а выполняется проверка пути к файлу. Открытие файла осуществляется в момент перезатирания файла.

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. Проверка в итоге бесполезна.

А почему бы просто не шифровать данные на лету в эти временные файлы? На производительности это почти не скажется и решает проблему/задачу скрытия данных.
Как вариант можно и шифровать. Многие использует поход шифрования.

Да, полностью поддерживаю.
Вопросы, которые остаются:


  1. алгоритм шифрования. При активной работе — может влиять на быстродействие, причем значительно. Но есть же более простые алгоритмы, которые аппаратно ускорены (AES-128?)
  2. вопрос хранения ключей шифровки-дешифровки.
создавайте файлы в RAM-диске, если не хотите оставлять следов
А он точно в своп не отсвопится?

От данных в свопе ничего, наверное, не спасет. И ничего не спасет от прямого лампа расшифрованных данных из ОЗУ. Надо просто проработать модель рисков — от кого защищаемся

От данных в свопе ничего, наверное, не спасет.

mlock(2) спасает. Данные в памяти можно надёжно спрятать от других процессов с помощью prctl(2) (PR_SET_DUMPABLE). На других системах есть свои аналоги. Остаётся доверие ядру ОС. Ну и rowhammer, а также физический доступ к машине. Но в целом оперативная память процесса — это самое безопасное место, после какого-нибудь TPM.

Причём тут Java, если почти всё написали на C++? На Java точно так же можно свободно в файл что угодно писать, хоть через FileOutputStream, хоть через NIO file channels.

Сначала в проекте решено было использовать утилиту secure-delete. Но нужно установить и проверить где установлена. Что не очень хорошо.
Потом подумали чтобы через JNI привязать код secure-delete. И так и сделали.
Но когда нужно было отлаживать, вот тогда стало плохо. Потому что в secure-delete очень много макросов.
Потом посмотрев на современный С++ решили реализовать на чистом С++.

Все равно непонятно. Записать нули или что-то рандомное/закриптованное в файл — тривиальная процедура на Джаве. Зачем же тащить в проект совершенно не нужный С++ код и лишний бинарник? Все как-то из пальца высосано.

this->file = kl::fs_util::make_open_file(file_name, «r+b»);
Если собираемся затирать файл почему «r+b»?

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

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

Не просто криптованные, а еще и экономящие место на диске через сжатие.

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

Публикации