用Python编写具有特定权限的文件
我试图创建一个只有用户可读写的文件(用Python编写具有特定权限的文件,python,file-io,permissions,Python,File Io,Permissions,我试图创建一个只有用户可读写的文件(0600) 使用os.open()的唯一方法是这样做吗 import os fd = os.open('/path/to/file', os.O_WRONLY, 0o600) myFileObject = os.fdopen(fd) myFileObject.write(...) myFileObject.close() 理想情况下,我希望能够将与关键字一起使用,以便自动关闭对象。有没有更好的方法来完成我上面的工作 更新 各位,虽然我感谢你们的支持,但我自己
0600
)
使用os.open()
的唯一方法是这样做吗
import os
fd = os.open('/path/to/file', os.O_WRONLY, 0o600)
myFileObject = os.fdopen(fd)
myFileObject.write(...)
myFileObject.close()
理想情况下,我希望能够将与
关键字一起使用,以便自动关闭对象。有没有更好的方法来完成我上面的工作 更新
各位,虽然我感谢你们的支持,但我自己也不得不反对我最初提出的解决方案。原因是这样做,无论文件存在的时间多么短,并且没有适当的权限,都会有一段时间——这会留下广泛的攻击途径,甚至出现错误行为。当然,首先创建具有正确权限的文件是一种方法——与此相反,使用Python的
和
只是一种糖果
所以,请把这个答案作为一个“不做什么”的例子
原创帖子
您可以改用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
>>>
(请注意,在Python中使用八进制的方法是显式的——在它前面加上“0o
”,就像在“0o600
”。在Python2.x中,只需编写0600
”就可以了——但这既有误导性又不推荐。)
但是,如果您的安全性很关键,您可能应该像使用
os.open
一样使用os.fdopen
从os.open返回的文件描述符中检索Python文件对象。问题是什么file.close()
将关闭该文件,即使该文件是使用os.open()
打开的
with os.fdopen(os.open('/path/to/file', os.O_WRONLY | os.O_CREAT, 0o600), 'w') as handle:
handle.write(...)
此答案解决了与的多个问题,尤其是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')
如果所需模式为0600
,则可以更清楚地将其指定为八进制数0o600
。更好的是,只需使用stat
模块
即使第一次删除了旧文件,竞争条件仍然是可能的。在标志中包含带有os.O_EXCL
的os.O_create
将阻止创建由于竞争条件而存在的文件。这是一种必要的二级安全措施,可防止打开可能已存在的文件,该文件可能具有提升的模式
。在Python 3中,如果文件存在,则会引发带有[Errno 17]的fileexisterror
如果未能首先将umask
设置为0
或0o777^模式
,可能会导致操作系统设置不正确的模式
(权限)。open
。这是因为默认的umask
通常不是0
,它将应用于指定的模式
。例如,如果我的原始umask
是2
,即0o002
,并且我指定的模式是0o222
,如果我未能首先设置umask
,则生成的文件可以改为具有0o220
的模式,这不是我想要的。根据man 2 open
,所创建文件的模式为模式&~umask
umask
将尽快恢复到其原始值。此获取和设置不是线程安全的,在多线程应用程序中必须使用线程.Lock
有关umask的更多信息,请参阅。我想建议对a-B-B的优秀答案进行修改,以更清楚地区分关注点。主要的优点是,您可以分别处理打开文件描述符期间发生的异常和实际写入文件期间的其他问题
外部<代码>请尝试。。。最后,
block在打开文件描述符时负责处理权限和umask
问题。内部with
块处理在使用Python文件对象时可能出现的异常(正如OP所希望的):
如果要附加到文件而不是写入,则应按如下方式打开文件描述符:
fdesc = os.open(outfname, os.O_WRONLY | os.O_CREAT | os.O_APPEND, 0o600)
with os.fdopen(fdesc, "a") as outf:
文件对象如下所示:
fdesc = os.open(outfname, os.O_WRONLY | os.O_CREAT | os.O_APPEND, 0o600)
with os.fdopen(fdesc, "a") as outf:
当然,所有其他常用的组合都是可能的。问题在于设置权限,以确保文件不具有全局可读性(仅对当前用户进行读/写)
不幸的是,代码本身:
fd = os.open('/path/to/file', os.O_WRONLY, 0o600)
不保证权限将被拒绝给世界。它确实尝试为当前用户设置r/w(前提是umask允许),仅此而已
在两个完全不同的测试系统上,这段代码创建了一个带有-rw-r--r--和-rw-rw--的文件,其中包含我的默认umask,以及带有umask(0)的-rw-rw--文件,这显然不是我们想要的(并且会带来严重的安全风险)
如果要确保文件没有为组和世界设置位,则必须首先对这些位进行umask(请记住-umask是拒绝权限):
此外,为了100%确保该文件不存在并具有不同的权限,您必须先对其进行chmod/删除(删除更安全,因为您可能在目标目录中没有写入权限-如果您有安全问题,您不希望在不允许写入的地方写入某些文件!),否则,如果黑客在您移动之前以全球r/w权限创建了文件,您可能会遇到安全问题。在这种情况下,os.open将在不设置权限的情况下打开该文件,您将得到一个世界r/w机密文件
因此,您需要:
import os
if os.path.isfile(file):
os.remove(file)
original_umask = os.umask(0o177) # 0o777 ^ 0o600
try:
handle = os.fdopen(os.open(file, os.O_WRONLY | os.O_CREAT, 0o600), 'w')
finally:
os.umask(original_umask)
无论您的环境和配置如何,这都是确保创建-rw-------文件的安全方法。当然,您可以根据需要捕获并处理IOR错误。如果您在目标目录中没有写入权限,则无法创建该文件,如果该文件已存在,则删除将失败。我会采取不同的做法
from contextlib import contextmanager
@contextmanager
def umask_helper(desired_umask):
""" A little helper to safely set and restore umask(2). """
try:
prev_umask = os.umask(desired_umask)
yield
finally:
os.umask(prev_umask)
# ---------------------------------- […] ---------------------------------- #
[…]
with umask_helper(0o077):
os.mkdir(os.path.dirname(MY_FILE))
with open(MY_FILE, 'wt') as f:
[…]
文件操作代码