Using umask to prevent world-readable password sniffing

Abstract

A brief note advocating the use of umask as best practice for dealing with password files on multi-user machines

The background: on a *nix system, traditionally all files are world-readable. This is good, and often useful. Putting passwords in clear-text files though is a perennial mistake and is often a problem at Cambridge for the SRCF. Commonly, users work around this by installing an application (say MediaWiki), then quickly changing the permissions on the configuration files generated where the database passwords are stored. Most years some malicious student or other runs a password-sniffing script and gets some passwords, but the probability of a nasty script running on any particular day is low, and it is very unlikely that a script running through files sequentially will spot anything in the short window the password is readable.

Unfortunately, this does procedure does not follow good practices and I suggest is easily enough exploitable to cause some concern. Scripts searching all files must necessarily take a lot of disk and CPU time, a much smaller, less likely to be detected script would lie largely dormant, grabbing a list of recently changed files each second from some inotify-like interface. Most files would be entirely ignored, and just a few likely-looking filenames (such as LocalSettings.php) would be picked up on.

The defense is actually rather easy, and explains the standard best practices approach to password files. Instead of making the file, then changing its permissions to not readable, leading to the vulnerability above, use umask to ensure the file is never readable in the first place.

For MediaWiki, this takes a little faff, for example. We need the first-run install page to load to generate the initial config, but it checks for the precence of LocalSettings.php to run that. So, that explains the procedure on the SRCF FAQ page which tells you to run the MediaWiki install process until the password form appears, then, before submitting it and generating the password file running these:

$ mkdir ~/<socname>/public_html/wiki/config
$ umask 0007
$ touch ~/<socname>/public_html/wiki/config/LocalSettings.php
$ chgrp <socname> ~/<socname>/public_html/wiki/config/LocalSettings.php
$ umask 0002

Then, submitting the form overwrites the blank password file, but leaves it with the same permissions.

Note

If you refuse to believe me that a script can read a non-readable file, run this simple example:

$ touch test
$ cat > test.py <<EOF
> import time;
> handle = open ('test.txt');
> while (True):
>         time.sleep(2);
>         handle.seek(0);
>         print handle.read();
> EOF
$ python test.py

Then in another terminal,

$ chmod ugo-r test

still leaves the first one reading the file, because permissions are only checked when handing out file handles, not each time they are used.