X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=developers-reference.sgml;h=8698e292cf5c22047500915027370c8cfb5b9660;hb=44e618bcf365a9652306644907b9e167a39c13b7;hp=f40c3586e5f28d6d60c84fecb4bb95fb147dd003;hpb=e0796005cf687245001464031e3ed2c5a06ddc5c;p=developers-reference.git diff --git a/developers-reference.sgml b/developers-reference.sgml index f40c358..8698e29 100644 --- a/developers-reference.sgml +++ b/developers-reference.sgml @@ -7,7 +7,7 @@ %dynamicdata; - + @@ -4060,388 +4060,6 @@ before the /usr partition is mounted. Most scripts won't have this problem, though. - - Best practices for security review and design - -

When you are packaging software for other users you should make a -best effort to ensure that the installation of the software, or its -use, does not introduce security risks to either the system it is -installed on or its users.

- -

You should make your best to review the source code of the package and -detect issues that might introduce security bugs. The programming bugs -which lead to security bugs typically include: , , and (in C/C++ programs), temporary (in scripts), and command injection (in servers) and , and (in the case of web-oriented applications).

- -

Some of these issues might not be easy to spot unless you are an -expert in the programming language the program uses, but some security -problems are easy to detect and fix. For example, finding temporary -race conditions in the source code can easily be done by running -grep -r "/tmp/" . in the source code replace -hardcoded filenames using temporary directories to calls to either -mktemp or tempfile in shell -scripts, in Perl scripts, -and in C/C++. You can also use - to assist to the security code review phase.

- -

When packaging software make sure that: - - - -The software runs with the minimum privileges it needs: - - -The package does install binaries setuid or setgid. -Lintian will warn of , - and binaries. - -The daemons the package provide run with a -low privilege user (see ) - - - -Programmed (i.e., cron) tasks running in the -system do NOT run as root or, if they do, do not implement complex -tasks. - - - -

If you have to do any of the above make sure the programs that -might run with higher privileges have been audited for security -bugs. If you are unsure, or need help, contact the . In the case of setuid/setgid binaries, follow the Debian -policy section regarding - -

- -

For more information, specific to secure programming, make sure you -read (or point your upstream to) and the portal. For more information specific to Debian security you can -read the -

- - - - - System users and groups for software daemons - -

If your software runs a daemon that does not need root privileges, -you need to create a user for it. There are two kind of Debian users -that can be used by packages: static uids (assigned by -base-passwd) and dynamic uids in the range assigned -to system users. - -

In the first case, you need to ask for a user or group id to the -base-passwd, and a proper versioned depends to the -base-passwd package that provides the user. - -

In the second case, you need to create the system user through maintainer -scripts. - -

Running programs with a user with limited privileges makes sure -that any security issue with the program makes limited damaged to the -system and follows the principle of least privilege you can -limit privileges in programs through other mechanisms besides running -as non-root. Fore more information, read the chapter of the Secure Programming for -Linux and Unix HOWTO book. - - - Creating system users and groups - -

If you want to create system groups on package installatino you -need to create it in either the preinst or in the postinst -and have the package depend on adduser (>= 3.11). - -

The following example code creates the user and group the daemon -will run as when the package is installed or upgraded: - - -[...] -case "$1" in - install|upgrade) - - # If the package has default file it could be sourced, so that - # the local admin can overwrite the defaults - # Notice that the package could handle this defaults through - # debconf so that the local admin could select a different - # user name for the system user than the one hardcoded in the - # package - - [ -f "/etc/default/packagename" ] && . /etc/default/packagename - - - # Sane defaults: - - [ -z "$SERVER_HOME" ] && SERVER_HOME=server_dir - [ -z "$SERVER_USER" ] && SERVER_USER=server_user - [ -z "$SERVER_NAME" ] && SERVER_NAME="Server description" - [ -z "$SERVER_GROUP" ] && SERVER_GROUP=server_group - - # Groups that the user will be added to, if undefined, then none. - # Some daemons might need additional privileges and those can be - # granted by adding it to additional groups. - ADDGROUP="" - - - # create user to avoid running server as root - # 1. create group if not existing - if ! getent group | grep -q "^$SERVER_GROUP:" ; then - echo -n "Adding group $SERVER_GROUP.." - addgroup --quiet --system $SERVER_GROUP 2>/dev/null ||true - echo "..done" - fi - # 2. create homedir if it does not exist - test -d $SERVER_HOME || mkdir $SERVER_HOME - # 3. create user if it does not exist - if ! getent passwd | grep -q "^$SERVER_USER:"; then - echo -n "Adding system user $SERVER_USER.." - adduser --quiet \ - --system \ - --ingroup $SERVER_GROUP \ - --no-create-home \ - --disabled-password \ - $SERVER_USER 2>/dev/null || true - echo "..done" - # 4. adjust passwd entry, only do this if the package - # creates the user - usermod -c "$SERVER_NAME" \ - -d $SERVER_HOME \ - -g $SERVER_GROUP \ - $SERVER_USER - else - # The package might want to check if the user already exists - # and it is *not* a system user, in this case it should abort - # the installation (like in this example) or ask the administrator - # since otherwrise it might have unexpected consequences. - # Some packages try to prevent collision by using a prefix such as 'Debian-' - for LINE in `grep SYSTEM_UID /etc/adduser.conf | grep -v "^#"`; do - case $LINE in - FIRST_SYSTEM_UID*) - FIST_SYSTEM_UID=`echo $LINE | cut -f2 -d '='` - ;; - LAST_SYSTEM_UID*) - LAST_SYSTEM_UID=`echo $LINE | cut -f2 -d '='` - ;; - *) - ;; - esac - done - # Abort package installation if the user has not been created by - # us. - if [ -n "$FIST_SYSTEM_UID" ] && [ -n "$LAST_SYSTEM_UID" ]; then - if USERID=`getent passwd $SERVER_USER | cut -f 3 -d ':'`; then - if [ -n "$USERID" ]; then - if [ "$FIST_SYSTEM_UID" -le "$USERID" ] && \ - [ "$USERID" -le "$LAST_SYSTEM_UID" ]; then - echo "The user $SERVER_USER already exists as a non system user!" >&2 - echo "Aborting package installation" >&2 - exit 1 - fi - fi - fi - fi - fi - - # 5. adjust file and directory permissions - # The example below sets the server home as 750 as it - # contains (hypothetically) sensible information. - if ! dpkg-statoverride --list $SERVER_HOME >/dev/null - then - chown -R $SERVER_USER:adm $SERVER_HOME - chmod u=rwx,g=rxs,o= $SERVER_HOME - fi - # 6. Add the user to the ADDGROUP group - if test -n $ADDGROUP - then - if ! groups $SERVER_USER | grep -q $ADDGROUP; then - adduser $SERVER_USER $ADDGROUP - fi - fi - ;; - configure) - -[...] - - - - Using system users - -

In order to make use of the system user you have to make sure that the -init.d script file: - - -Starts the daemon dropping privileges, if the software does not -do the or call itself, you can use the --chuid -call of start-stop-daemon. - -Stops the daemon only if the user id matches, you can use the -start-stop-daemon --user option -for this. - -Does not run if either the user or the group do not exist: - - if getent passwd | grep -q "^server_user:"; then - echo "Server user does not exist. Aborting" >&2 - exit 1 - fi - if getent group | grep -q "^server_group:" ; then - echo "Server group does not exist. Aborting" >&2 - exit 1 - fi - - - - -

File ownerships of files shipped by the package will need to be adjusted: - - -Configuration files should be readable by the system user, if they -contain sensitive information the system user should not own them unless there -is a need for it to write to its own configuration files. Typically this means -that the configuration files are owned by group, belong to the group of the -system user and are mode 0640. - -The system user if it generates state files (such as pidfiles) should -have a directory under /var/run owned by it. This directory should be -recreated by the init.d script since the state directory might be wiped out -after a system boot. - -If the daemon logs directly to /var/log logfiles should be -writable by the system user but, once rotated, they should not be either owned -or writable by it to prevent it from overwritting old log entries if a security -vulnerability in the software were to be used. If the daemon logs to a -directory under /var/log/ then it should be owned by the system user -and rotated log files need not be changed ownership. - - - - - Removing system users - -

If the package creates the system user it can remove it when it is -purged in its postrm script. This currently not recommended -since it has a few known - -Some relevant threads discussing these issues include: -, - -and -. - -drawbacks. For example, files created by the daemon (or by an admin -impersonating it) either on the local filesystem or in backup files will be -orphaned and might be taken over by a new system user in the future if it is -assigned the same uid. On the other hand, an unused local system user can be -used to access even if the account has been locked (as some authentication -systems might not use PAM or shadow authentication). - -

If you want to remove a system user and there is a possibility of it -leaving orphaned files, the administrator should be asked for the preferred -action either when the package is installed or when it is removed (see ). - -

The following example code removes the user and groups created -before only, and only if, the uid is in the range of dynamic assigned system -uids and the gid is belongs to a system group: - - -case "$1" in - purge) -[...] - # find first and last SYSTEM_UID numbers - if [ -r /etc/adduser.conf ] ; then - for LINE in `grep SYSTEM_UID /etc/adduser.conf | grep -v "^#"`; do - case $LINE in - FIRST_SYSTEM_UID*) - FIST_SYSTEM_UID=`echo $LINE | cut -f2 -d '='` - ;; - LAST_SYSTEM_UID*) - LAST_SYSTEM_UID=`echo $LINE | cut -f2 -d '='` - ;; - *) - ;; - esac - done - else - # Sane defaults - FIRST_SYSTEM_UID=100 - LAST_SYSTEM_UID=499 - fi - # Remove system account if it is a system user - CREATEDUSER="server_user" - if [ -n "$FIST_SYSTEM_UID" ] && [ -n "$LAST_SYSTEM_UID" ]; then - if USERID=`getent passwd $CREATEDUSER | cut -f 3 -d ':'`; then - if [ -n "$USERID" ]; then - if [ "$FIST_SYSTEM_UID" -le "$USERID" ] && \ - [ "$USERID" -le "$LAST_SYSTEM_UID" ]; then - echo -n "Removing $CREATEDUSER system user.." - deluser --quiet $CREATEDUSER || true - echo "..done" - fi - fi - fi - fi - # Remove system group if is a system group - CREATEDGROUP=server_group - if [ -r /etc/adduser.conf ] ; then - FIRST_USER_GID=`grep ^USERS_GID /etc/adduser.conf | cut -f2 -d '='` - else - # Sane defaults - FIRST_USER_GID=1000 - fi - if [ -n "$FIST_USER_GID" ] then - if GROUPGID=`getent group $CREATEDGROUP | cut -f 3 -d ':'`; then - if [ -n "$GROUPGID" ]; then - if [ "$FIST_USER_GID" -gt "$GROUPGID" ]; then - echo -n "Removing $CREATEDGROUP group.." - delgroup --only-if-empty $CREATEDGROUP || true - echo "..done" - fi - fi - fi - fi -[...] - - -

Other possibilities, are to make sure the account is locked (has an invalid -password and /bin/false as a shell) and modify the GECOS field -pointing out that the account is no longer used. - - - - Configuration management with debconf