Java-эквивалент для mkstemp

Есть ли какой-либо способ в Java безопасно записывать во временный файл?

Насколько я могу судить, единственный способ создать временный файл (createTempFile) на самом деле открывает его в одно и то же время, поэтому существует условие гонки между открытием файла и записью файла. Я что-то упускаю? Я не смог найти исходный код C вместо createFileExclusive (String) в UnixFileSystem.java, но я сомневаюсь, что он действительно может что-либо сделать, поскольку файл открывается в коде Java после создания файла temp (если он не пытается что-то сделать с файловые блокировки?).

Проблема

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

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

Надеюсь, смягчающим фактором является то, что Java правильно задала umask, поэтому менее привилегированный пользователь не может читать/записывать в файл, и обычно каталог /tmp правильно разрешает права доступа, чтобы вы не могли выполнить атаку unlink.

Конечно, если вы передадите пользовательский каталог временного файла, принадлежащего менее привилегированному пользователю, который скомпрометирован, пользователь может сделать атаку unlink против вас. Черт, с inotify, возможно, даже легче использовать условие гонки, чем просто цикл грубой силы, который делает список каталогов.

Ответ 1

http://kurt.seifried.org/2012/03/14/creating-temporary-files-securely/

Java

использовать java.io.File.createTempFile() - интересная информация на http://www.veracode.com/blog/2009/01/how-boring-flaws-become-interesting/

для каталогов есть полезная публикация в Как создать временную папку/папку на Java?

Java 7

для файлов используется java.io.File.createTempFile()

для каталогов используется createTempDirectory()

http://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html

Ответ 2

Имейте в виду, что во многих системах просто потому, что файл не имеет имени, вовсе не означает, что он недоступен. Например, в Linux открытые дескрипторы файлов доступны в /proc/<pid>/fd/<fdno>. Поэтому вы должны убедиться, что использование временных файлов безопасно, даже если кто-то знает/имеет ссылку на открытый файл.

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

Ответ 3

Защита от других обычных пользователей? Да, на любой правильно функционирующей многопользовательской системе.

Защитите свой собственный идентификатор пользователя или суперпользователя? Нет.

Ответ 4

С Java 7 мы OpenOption.

Объект, который настраивает способ открытия или создания файла.

Объекты этого типа используются при использовании таких методов, как newOutputStream, newByteChannel, FileChannel.open и AsynchronousFileChannel.open при открытии или создании файла.

Особый интерес представляет StandardOpenOptions.CREATE_NEW.

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

Итак, вы можете сделать что-то вроде этого:

FileChannel mkstemp() {
    Path path = Files.createTempFile(null, null);
    Files.delete(path);
    return FileChannel.open(path, WRITE, CREATE_NEW);
}

Реализация одного и того же поведения шаблона остается как упражнение для читателя.