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

我试图创build一个只有用户可读和可写的文件( 0600 )。

是通过使用os.open()如下所示的唯一方法?

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

理想情况下,我想能够使用with关键字,以便我可以自动closures对象。 有没有更好的方式来做我在上面做的事情?

有什么问题? 即使使用os.open()打开文件, file.close()也会closures该文件。

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

这个回答解决了vartec的多个问题,特别是umask关注。 它也考虑到user465139的反馈 。

 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 in octal and 384 in decimal. # For security, remove file with potentially elevated mode try: os.remove(fname) except OSError: pass # Open file descriptor umask_original = os.umask(0) 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_EXCLos.O_CREAT将防止文件由于竞争条件而存在。 这是一个必要的辅助安全措施,以防止打开一个可能已经存在的可能提升mode 。 在Python 3中,如果文件存在,则引发FileExistsError和[Errno 17]。

无法首先将umask设置为0可能会导致由os.open设置不正确的mode (权限)。 这是因为默认的umask通常不是0 ,它可能会被应用到指定的mode 。 例如,如果我原来的umask2 ,而我指定的模式是0o222 ,如果我不能首先设置umask0 ,那么生成的文件可能会改为0o220mode ,这不是我想要的。 每人man 2 open ,创build的文件的mode & ~umaskmode & ~umask

umask尽快恢复到原始值。 这个获取和设置不是线程安全的,必要时使用threading.Lock

请注意,即使暂时将umask设置为0也是一个值得商榷的做法。 有关相关背景,请参阅此主题 。

更新民间,虽然我感谢你在这里upvotes,我自己不得不反对我最初提出的解决scheme下面。 原因就是这样做,会有一定的时间,无论文件是否存在,并且没有适当的权限 – 这会留下广泛的攻击方式,甚至是越野行为。
当然,首先创build具有正确权限的文件就是要走的路 – 违背正确性,使用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 >>> 

(请注意,在Python中使用八进制的方式是明确的 – 在“ 0o600 ”中加上“ 0o ”前缀,而在Python 2.x中它只能编写0600 ,但这是误导性的,也不推荐使用)。

但是,如果您的安全性至关重要,则您可能应该使用os.open创build它,并使用os.fdopenos.open返回的os.open检索Python File对象。

问题是关于设置权限,以确保文件不会是世界可读的( 只能为当前用户读/写 )。

不幸的是,它自己的代码是:

 fd = os.open('/path/to/file', os.O_WRONLY, 0o600) 

并不保证权限将被拒绝给世界。 它确实保证文件将有r / w 的当前用户 ,就是这样!

在两个完全不同的testing系统上,这段代码使用-rw-r -r-创build一个带有默认umask的文件,使用umask(0)创build-rw-rw-rw-这个文件绝对不是我们想要的(和姿势严重的安全风险)。

如果你想确保文件没有设置组和世界的位,你必须首先掩饰这些位(记住 – umask是否认权限):

 os.umask(0o177) 

此外,为了100%确定文件不是以不同的权限存在的,你必须先chmod / delete(删除更安全,因为你可能没有目标目录的写权限 – 如果你有安全问题,您不想在不允许的情况下写入文件!),否则如果黑客在您之前使用世界范围的r / w权限创build文件,则可能会遇到安全问题。 在这种情况下,os.open将会打开文件而不设置它的权限,而你只剩下一个世界上的密钥文件。

所以你需要:

 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) 

这是确保创build-rw ——-文件的安全方式,无论您的环境和configuration如何。 当然你也可以根据需要来处理IOErrors。 如果在目标目录中没有写入权限,则不能创build该文件,如果已经存在,则删除将失败。

我想build议对ABB的优秀答案进行修改,使问题更加清晰。 主要的好处是,在实际写入文件的过程中,可以处理在打开文件描述符时发生的exception与其他问题分开的情况。

外部try ... finally块在打开文件描述符的同时处理权限和umask问题。 内部with块处理可能的exception,同时处理Python文件对象(因为这是OP的愿望):

 try: oldumask = os.umask(0) fdesc = os.open(outfname, os.O_WRONLY | os.O_CREAT, 0o600) with os.fdopen(fdesc, "w") as outf: # ...write to outf, closes on success or on exceptions automatically... except IOError, ... : # ...handle possible os.open() errors here... finally: os.umask(oldumask) 

如果你想追加到文件而不是写入,那么文件描述符应该像这样打开:

 fdesc = os.open(outfname, os.O_WRONLY | os.O_CREAT | os.O_APPEND, 0o600) 

和这样的文件对象:

 with os.fdopen(fdesc, "a") as outf: 

当然,所有其他通常的组合都是可能的。