需求背景
用python进行文件的创建和读写操作时,我们很少关注所创建的文件的权限配置。对于一些安全性较高的系统,如果我们创建的文件权限其他用户或者同一用户组里的其他用户有可读权限的话,有可能导致不必要的信息泄漏的风险。因此,除了创建一个更加安全和隐私的个人环境之外(如容器环境等),我们还可以对生成的文件的配置进行权限最小化处理。
常用方法及其缺陷分析
常用的python文件创建和读写方法,是直接通过内置的open
函数创建一个文件。这里如果是使用with
语法来创建的,结束语句后会自动关闭被打开的对象。而如果是直接使用open
函数来定义一个对象,则需要在任务结束时手动的执行close
操作。以下演示内置函数open
的用法及其文件操作属性,首先创建一个名为file-test.py
的文件:
# file-test.py
with open('test1.txt', 'w') as file:
file.write('hello world!')
该任务的内容为:在当前目录下创建一个名为test1.txt
的文件,清空该文件的内容后,在文件中写入hello world!
这个字符串。接下来用python3
执行该文件:
[dechin@dechin-manjaro os_security]$ python3 file-test.py
[dechin@dechin-manjaro os_security]$ ll
总用量 8
-rw-r--r-- 1 dechin dechin 83 1月 25 13:43 file-test.py
-rw-r--r-- 1 dechin dechin 12 1月 25 13:43 test1.txt
这里我们发现,在执行之后成功产生了test1.txt
这个文件,其权限配置为644
,与前面创建的file-test.py
保持一致。在不清楚内置函数open
的实现原理时,原本以为这个产生的文件权限配置是与当前的py
文件保持一致的。然而经过进一步的测试,将py
文件的权限配置为440
之后再重新执行该文件:
[dechin@dechin-manjaro os_security]$ chmod 440 file-test.py
[dechin@dechin-manjaro os_security]$ ll
总用量 8
-r--r----- 1 dechin dechin 83 1月 25 13:43 file-test.py
-rw-r--r-- 1 dechin dechin 12 1月 25 13:43 test1.txt
[dechin@dechin-manjaro os_security]$ rm test1.txt
[dechin@dechin-manjaro os_security]$ python3 file-test.py
[dechin@dechin-manjaro os_security]$ ll
总用量 8
-r--r----- 1 dechin dechin 83 1月 25 13:43 file-test.py
-rw-r--r-- 1 dechin dechin 12 1月 25 13:44 test1.txt
这里从测试结果我们可以看出,python的内置函数open
产生的文件类型是与源py
文件无关的。关于这里py
文件的执行是否需要可执行权限,可以参考这篇博客。
改进后的python文件创建方法
通过fdopen
这个库以及特殊的权限指定,我们可以设置生成文件的访问权限,以下直接展示一个python代码案例:
# fdopen-test.py
import os
import stat
file_name = 'test2.txt'
flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL
mode = stat.S_IRUSR | stat.S_IWUSR
with os.fdopen(os.open(file_name, flags, mode), 'w') as file:
file.write('hello world!')
执行之后我们可以发现,当前目录下生成了一个名为test2.txt
的文件,其权限配置为600
, 对照于我们在代码中设置的mode = stat.S_IRUSR | stat.S_IWUSR
。这里我们先对其中的一些参数作一个解释:os.O_WRONLY
表示以只写的方式打开,os.O_CREAT
表示创建并打开一个新文件,os.O_EXCL
表示如果文件已存在则报错。而mode
中所配置的权限分别对应rwx
配置,其中USR,GRP,OTH
又分别对用户、用户组、其他用户
进行了细分的配置,从而我们就可以通过改变mode
参数来实现所有种类的权限配置。
我们可以尝试将上述用例中的mode
作一个调整,比如添加一个可执行权限变为700
:
# fdopen-test.py
import os
import stat
file_name = 'test3.txt'
flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL
mode = stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR
with os.fdopen(os.open(file_name, flags, mode), 'w') as file:
file.write('hello world!')
又或者,我们需要为用户组里的其他用户添加可访问权限,比如640
权限:
# fdopen-test.py
import os
import stat
file_name = 'test4.txt'
flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL
mode = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP
with os.fdopen(os.open(file_name, flags, mode), 'w') as file:
file.write('hello world!')
甚至我们也可以写出系统原生的644
文件权限:
# fdopen-test.py
import os
import stat
file_name = 'test5.txt'
flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL
mode = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH
with os.fdopen(os.open(file_name, flags, mode), 'w') as file:
file.write('hello world!')
最后,让我们一起看下上面这些python示例执行后得到的结果:
[dechin@dechin-manjaro os_security]$ ll
总用量 28
-rw-r--r-- 1 dechin dechin 269 1月 25 14:58 fdopen-test.py
-r--r----- 1 dechin dechin 84 1月 25 14:11 file-test.py
-rw-r--r-- 1 dechin dechin 12 1月 25 13:44 test1.txt
-rw------- 1 dechin dechin 12 1月 25 14:44 test2.txt
-rwx------ 1 dechin dechin 12 1月 25 14:48 test3.txt
-rw-r----- 1 dechin dechin 12 1月 25 14:56 test4.txt
-rw-r--r-- 1 dechin dechin 12 1月 25 14:58 test5.txt
从结果中我们可以看出,所有产生的文件test*.txt
都按照我们预期的文件权限配置生成,到这里我们就完成了所有预期的目标。
总结概要
使用python进行文件的创建和读写时,常规的内置函数open
得到的结果会是一个644
权限的文件,这不一定能够满足很多对安全性需求较高的执行环境的要求。因此我们可以通过fdopen
来对所创建的文件进行进一步的权限约束,具体的操作方法可以在mode
中定义一系列的权限配置,比如带有USR
的表示当前用来执行python文件的用户,带有GRP
的表示用来执行python文件的整个用户组,而OTH
则表示其他的所有的用户。这当中尤其是OTH
这个选项往往是不必要开放的权限,我们也可以根据具体的场景需求对创建的文件权限进行配置。这里还有一点补充介绍的是,os.O_EXCL
这个指令的开启表示如果存在同名文件就无法创建,需要先使用os.remove
操作删除原文件后再进行新的文件操作,避免文件权限被覆盖或者重用,从而导致创建的新文件权限配置与我们所预期的不符合。
参考链接
- fdopen使用方法的问答
- os.open()各配置参数解释
版权声明
本文首发链接为:https://www.cnblogs.com/dechinphy/p/fdopen.html
作者ID:DechinPhy
更多原著文章请参考:https://www.cnblogs.com/dechinphy/