Как гарантировать, что файлы, которые расшифровываются во время выполнения, очищаются? - PullRequest
3 голосов
/ 10 ноября 2008

Используя C или C ++, после того, как я расшифровал файл на диск - как я могу гарантировать, что он будет удален в случае сбоя приложения или выключения системы и невозможности его очистки? Использование C или C ++, в Windows и Linux?

Ответы [ 13 ]

7 голосов
/ 10 ноября 2008

К сожалению, нет 100% надежного способа гарантировать, что файл будет удален в случае полного сбоя системы. Подумайте о том, что произойдет, если пользователь просто нажмет на вилку, пока файл находится на диске. Никакая обработка исключений не защитит вас от этого (наихудшего) случая.

Лучшее, что вы можете сделать, это не записывать дешифрованный файл на диск. Если файл существует как в зашифрованном, так и в зашифрованном виде, это слабое место в вашей безопасности.

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

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

5 голосов
/ 10 ноября 2008

Не записывать файл, расшифрованный на диск вообще.

Если система выключена, файл все еще находится на диске, поэтому к диску можно получить доступ к файлу.

Исключением может быть использование зашифрованной файловой системы, но это не зависит от вашей программы.

4 голосов
/ 10 ноября 2008

Я не знаю, работает ли это в Windows, но в Linux, предполагая, что вам нужен только один процесс для доступа к расшифрованному файлу, вы можете открыть файл и затем вызвать unlink (), чтобы удалить файл. Файл будет продолжать существовать до тех пор, пока процесс будет держать его открытым, но когда он будет закрыт или процесс умирает, файл больше не будет доступен.

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

4 голосов
/ 10 ноября 2008

Старайтесь избегать этого полностью:

Если файл является чувствительным, лучше всего не записывать его на диск в дешифрованном формате.

Защита от сбоев: структурированная обработка исключений:

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

__ пробовать и __except

Что, если они потянут за вилку?:

Есть способ защититься от этого ...

Если вы находитесь в Windows, вы можете использовать MoveFileEx и опцию MOVEFILE_DELAY_UNTIL_REBOOT с целевым значением NULL, чтобы удалить файл при следующем запуске. Это защитит от случайного выключения компьютера с помощью удаленного файла. Вы также можете убедиться, что у вас есть исключительно открытый дескриптор этого файла (не указывайте права на совместное использование, такие как FILE_SHARE_READ и используйте CreateFile, чтобы открыть его). Таким образом, никто не сможет читать с него.

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

  • Вы также можете рассмотреть возможность записи в файл, размер которого превышает MAX_PATH, используя синтаксис файла \\? \. Это обеспечит невозможность просмотра файла проводником Windows.

  • Вы должны установить для файла временный атрибут

  • Вы должны установить для файла скрытый атрибут

2 голосов
/ 10 ноября 2008

В C (и, я полагаю, в C ++), пока ваша программа не падает, вы можете зарегистрировать обработчик atexit() для очистки. Просто избегайте использования _exit() или _Exit(), поскольку они обходят обработчики atexit().

Однако, как отмечали другие, лучше избегать записи расшифрованных данных на диск. И просто использование unlink() (или эквивалент) недостаточно; вам нужно переписать некоторые другие данные поверх исходных данных. И журналированные файловые системы делают это очень трудным.

1 голос
/ 11 ноября 2008

В C ++ вы должны использовать тактику RAII :

class Clean_Up_File {
    std::string filename_;
    public Clean_Up_File(std::string filename) { ... } //open/create file
    public ~Clean_Up_File() { ... } //delete file
}

int main()
{
    Clean_Up_File file_will_be_deleted_on_program_exit("my_file.txt");
}

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

Но, как уже упоминали другие, это работает только при "нормальных" обстоятельствах. Если пользователь отключит компьютер, вы не сможете гарантировать, что файл будет удален. И может быть возможно восстановить файл (даже в UNIX возможно " grep the harddrive ").


Кроме того, как указано в комментариях, в некоторых случаях объекты не выпадают из области видимости (например, функция std::exit(int) выходит из программы, не выходя из текущей области видимости), поэтому RAII не работает в тех случаях. Лично я никогда не вызываю std::exit(int), и вместо этого я либо выбрасываю исключения (которые раскрутят стек и вызовет деструкторы; что я считаю «ненормальным выходом»), либо верну код ошибки из main() (который вызовет деструкторы и который Я тоже считаю "ненормальный выход"). IIRC, отправка SIGKILL также не вызывает деструкторов, и SIGKILL не может быть пойман, поэтому вам тоже не повезло.

1 голос
/ 10 ноября 2008

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

Когда-нибудь видели эти шпионские фильмы, где они перезаписывают жесткий диск 6, 8,24 раза, и вот как они узнают, что он чистый ... Ну, они делают это по причине. Я приложил бы все усилия, чтобы не хранить расшифрованные данные файла. Или, если нужно, внесите небольшие объемы данных. Даже несвязные данные.

Если вы должны, тогда они пытаются поймать, должны немного защитить вас .. Хотя ничто не может защитить от перебоев в питании.

Удачи.

1 голос
/ 10 ноября 2008

Проверьте tmpfile ().

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

Запись в файловую систему (даже временно) небезопасна.
Делайте это, только если вам действительно нужно.

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

1 голос
/ 10 ноября 2008

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

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

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

Становится очевидным, что вам нужен какой-то механизм блокировки, чтобы предотвратить переключение на файл подкачки / раздел подкачки. В Posix Systems это можно сделать с помощью m(un)lock* family of functions.

0 голосов
/ 15 ноября 2008

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

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

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

Эта реализация не требует от меня расшифровки в файл или в память и совместима с другими потребителями и поставщиками потоков (fstream).

Это мой «план». Я не работал с fstream такого рода раньше, и я, скорее всего, опубликую вопрос, как только буду готов работать над этим.

Спасибо за все остальные ответы - это было очень информативно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...