Reputation: 191
The documentation for the os
module makes the following assertion:
Note
Using access() to check if a user is authorized to e.g. open a file before actually doing so using open() creates a security hole, because the user might exploit the short time interval between checking and opening the file to manipulate it. It’s preferable to use EAFP techniques. For example:
if os.access("myfile", os.R_OK):
with open("myfile") as fp:
return fp.read()
return "some default data"`
is better written as:
try:
fp = open("myfile")
except PermissionError:
return "some default data"
else:
with fp:
return fp.read()
I don't understand how a user "might exploit" the interval. If open
was going to raise an exception, I'm not sure how os.access
would prevent that exception from being raised. Likewise, if the user manipulate the file somehow, why not perform the file manipulation prior to the EAFP version's open
command?
I do understand that the second version may be more robust, since os.access
may fail to correctly recognize a condition that could raise a PermissionError
, but I don't see how the LBYL version is less secure. Can someone explain this?
Upvotes: 8
Views: 352
Reputation: 281586
While the access
-using code is unsafe, the second code snippet doesn't solve the security issues. These docs should be changed.
The purpose of os.access
is to test whether the real user id has permission to access a file when the real and effective user ids are different. The danger with the os.access
snippet is that the user could place a file access
returns True
for in the location being tested, then swap it out for a file access
would have returned False
for, bypassing the check. Since open
uses the effective user id, the open
call can still work, bypassing the access
check.
The second snippet doesn't solve this problem. Now the user doesn't even need to go through the switcheroo. No part of the second snippet checks the real user id.
Upvotes: 8