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)
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_EXCL
与os.O_CREAT
如果存在因竞争条件的标志将防止创建的文件.这是一种必要的辅助安全措施,可防止打开可能已存在且可能已升高的文件mode
.在Python 3中,FileExistsError
如果文件存在,则引发[Errno 17].
未能首先设置umask
to 0
或to 0o777 ^ mode
可能导致设置不正确mode
(权限)os.open
.这是因为默认umask
值通常不是0
,它将应用于指定的mode
.例如,如果我原来umask
是2
即0o002
和我指定的模式是0o222
,如果我不先设置umask
,生成的文件可以改为具有mode
的0o220
,这不是我想要的东西.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
.