在Python中编写具有特定权限的文件

lfa*_*one 51 python permissions file-io

我正在尝试创建一个只有用户可读和可写(0600)的文件.

这是通过以下方式使用的唯一方法os.open()吗?

import os
fd = os.open('/path/to/file', os.O_WRONLY, 0o600)
myFileObject = os.fdopen(fd)
myFileObject.write(...)
myFileObject.close()
Run Code Online (Sandbox Code Playgroud)

理想情况下,我希望能够使用with关键字,以便我可以自动关闭对象.有没有更好的方法来做我上面做的事情?

var*_*tec 36

有什么问题?file.close()将关闭该文件,即使它已打开os.open().

with os.fdopen(os.open('/path/to/file', os.O_WRONLY | os.O_CREAT, 0o600), 'w') as handle:
  handle.write(...)
Run Code Online (Sandbox Code Playgroud)

  • 我认为这个答案比我的好,但它不是"问题所在":你提出了一个OP不知道的新因素 - 即将文件处理程序转换为Python文件对象 (3认同)
  • @vartec,这个答案有一个'umask`特定的问题.我已经发布了一个答案来解决这个问题. (2认同)

Acu*_*nus 28

这个答案解决了vartec答案的多重顾虑,尤其是umask关注点.

import os
import stat

# Define file params
fname = '/tmp/myfile'
flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL  # Refer to "man 2 open".
mode = stat.S_IRUSR | stat.S_IWUSR  # This is 0o600.
umask = 0o777 ^ mode  # Prevents always downgrading umask to 0.

# For security, remove file with potentially elevated mode
try:
    os.remove(fname)
except OSError:
    pass

# Open file descriptor
umask_original = os.umask(umask)
try:
    fdesc = os.open(fname, flags, mode)
finally:
    os.umask(umask_original)

# Open file handle and write to file
with os.fdopen(fdesc, 'w') as fout:
    fout.write('something\n')
Run Code Online (Sandbox Code Playgroud)

如果是所需模式0600,则可以更明确地将其指定为八进制数0o600.更好的是,只需使用该stat模块.

即使首先删除旧文件,仍然可以进行竞争条件.包括os.O_EXCLos.O_CREAT如果存在因竞争条件的标志将防止创建的文件.这是一种必要的辅助安全措施,可防止打开可能已存在且可能已升高的文件mode.在Python 3中,FileExistsError如果文件存在,则引发[Errno 17].

未能首先设置umaskto 0或to 0o777 ^ mode可能导致设置不正确mode(权限)os.open.这是因为默认umask值通常不是0,它将应用于指定的mode.例如,如果我原来umask20o002和我指定的模式是0o222,如果我不先设置umask,生成的文件可以改为具有mode0o220,这不是我想要的东西.Per man 2 open,创建文件的模式是mode & ~umask.

umask是尽快恢复到原来的值.此获取和设置不是线程安全的,并且threading.Lock必须在多线程应用程序中使用.

有关umask的更多信息,请参阅此主题.


jsb*_*eno 12

更新 人们,虽然我感谢你们在这里的赞成,我自己不得不反对我最初提出的解决方案.原因在于以这种方式做事,文件确实存在时会有一段时间,无论多么小,并且没有适当的权限 - 这会留下广泛的攻击方式,甚至是错误的行为.
当然,首先使用正确的权限创建文件是要走的路 - 正确性,使用Python with只是一些糖果.

所以,请把这个答案作为"什么不该做"的例子;

原帖

你可以os.chmod改用:

>>> import os
>>> name = "eek.txt"
>>> with open(name, "wt") as myfile:
...   os.chmod(name, 0o600)
...   myfile.write("eeek")
...
>>> os.system("ls -lh " + name)
-rw------- 1 gwidion gwidion 4 2011-04-11 13:47 eek.txt
0
>>>
Run Code Online (Sandbox Code Playgroud)

(请注意,在Python中使用octals的方法是明确的 - 通过在"\n"中添加前缀0o" 0o600".在Python 2.x中它只能编写0600- 但这既误导又弃用.)

但是,如果您的安全性很关键,那么您可能应该os.open像使用它一样创建它并使用os.fdopen从返回的文件描述符中检索Python File对象os.open.