Package: developers-reference Version: 3.3.6 Tags: patch Attached is a patch that provides a list of best practices for security review and designed. If there is no intention to add this to the Developer Reference please say so, if that is the case, I will simply create a new section in the "Securing Debian Manual" oriented towards package developers. Javier
Index: developers-reference.sgml =================================================================== RCS file: /cvs/debian-doc/ddp/manuals.sgml/developers-reference/developers-reference.sgml,v retrieving revision 1.282 diff -u -r1.282 developers-reference.sgml --- developers-reference.sgml 2 Nov 2005 08:11:32 -0000 1.282 +++ developers-reference.sgml 2 Nov 2005 15:51:34 -0000 @@ -4060,6 +4060,415 @@ this problem, though. </sect> + <sect id="bpp-debian-security-audit"> + <heading>Best practices for security review and design</heading> + +<p>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.</p> + +<p>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: <url +id="http://en.wikipedia.org/wiki/Buffer_overflow" name="buffer +overflows">, <url +id="http://en.wikipedia.org/wiki/Cross_site_scripting" name="format +string overflows">, <url +id="http://en.wikipedia.org/wiki/Cross_site_scripting" name="heap +overflows"> and <url +id="http://en.wikipedia.org/wiki/Cross_site_scripting" name="integer +overflows"> (in C/C++ programs), temporary <url +id="http://en.wikipedia.org/wiki/Symlink_race" name="symlink race +conditions"> (in scripts), <url +id="http://en.wikipedia.org/wiki/Directory_traversal" name="directory +traversal"> and command injection (in servers) and <url +id="http://en.wikipedia.org/wiki/Cross_site_scripting" +name="cross-site scripting">, and <url +id="http://en.wikipedia.org/wiki/Cross_site_scripting" name="SQL +injection bugs"> (in the case of web-oriented applications).</p> + +<p>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 +<tt>grep -r "/tmp/" .</tt> in the source code replace +hardcoded filenames using temporary directories to calls to either +<prgn>mktemp</prgn> or <prgn>tempfile</prgn> in shell +scripts, <manref name="File::Temp" section="3perl"> in Perl scripts, +and <manref name="tmpfile" section="3"> in C/C++. You can also use +<url id="http://www.debian.org/security/audit/tools" name="specific +tools"> to assist to the security code review phase.</p> + +<p>When packaging software make sure that: + +<list> + +<item>The software runs with the minimum privileges it needs: + +<list> +<item>The package does install binaries setuid or setgid. +<prgn>Lintian</prgn> will warn of <url id=" +http://lintian.debian.org/reports/Tsetuid-binary.html" name="setuid">, +<url id="http://lintian.debian.org/reports/Tsetgid-binary.html" +name="setgid"> and <url +id="http://lintian.debian.org/reports/Tsetuid-gid-binary.html" +name="setuid and setgid"> binaries. + +<item>The daemons the package provide run with a +low privilege user (see <ref id="bpp-lower-privs">) + +</list> + +<item>Programmed (i.e., <prgn>cron</prgn>) tasks running in the +system do NOT run as root or, if they do, do not implement complex +tasks. + +</list> + +<p>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 <url +id="http://www.debian.org/security/audit/" name="Debian Security Audit +team">. In the case of setuid/setgid binaries, follow the Debian +policy section regarding +<url id="http://www.debian.org/doc/debian-policy/ch-files.html#s10.9" +name="permissions and owners"> +</p> + +<p>For more information, specific to secure programming, make sure you +read (or point your upstream to) <url +id="http://www.dwheeler.com/secure-programs/" name="Secure Programming +for Linux and Unix HOWTO"> and the <url +id="https://buildsecurityin.us-cert.gov/portal/" name="Build Security +In"> portal. For more information specific to Debian security you can +read the <url +id="http://www.debian.org/doc/manuals/securing-debian-howto/" +name="Debian Security Manual"> +</p> + +<!-- This should be explained here until #291177 gets fixed and this is + added to poliy --> + + <sect1 id="bpp-lower-privs"> + <heading>System users and groups for software daemons + +<p>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 +<package>base-passwd</package>) and dynamic uids in the range assigned +to system users. + +<p>In the first case, you need to ask for a user or group id to the +<package>base-passwd</package>, and a proper versioned depends to the +<package>base-passwd</package> package that provides the user. + +<p>In the second case, you need to create the system user through maintainer +scripts. <url id="http://www.debian.org/doc/debian-policy/ch-files.html#s10.9" +name="policy"> requires you discuss an appropiate user and group name on +<em>debian-devel</em> and make sure it is unique and does not overlap +with other packages. + +<p>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 <em>least privilege</em> you can +limit privileges in programs through other mechanisms besides running +as non-root. Fore more information, read the <url +id="http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/minimize-privileges.html" +name="Minimize Privileges"> chapter of the <em>Secure Programming for +Linux and Unix HOWTO</em> book. + + <sect2 id="bpp-create-sysuser"> + <heading>Creating system users and groups + +<p>If you want to create system groups on package installation you +need to create it in either the <em>preinst</em> or in the <em>postinst</em> +and have the package depend on <tt>adduser (>= 3.11)</tt>. + +<p>The following example code creates the user and group the daemon +will run as when the package is installed or upgraded: + +<example> +[...] +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/<var>packagename</var>" ] && . /etc/default/<var>packagename</var> + + + # Sane defaults: + + [ -z "$SERVER_HOME" ] && SERVER_HOME=<var>server_dir</var> + [ -z "$SERVER_USER" ] && SERVER_USER=<var>server_user</var> + [ -z "$SERVER_NAME" ] && SERVER_NAME="<var>Server description</var>" + [ -z "$SERVER_GROUP" ] && SERVER_GROUP=<var>server_group</var> + + # 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 system group $SERVER_GROUP.." + addgroup --quiet --system $SERVER_GROUP + if ! getent group | grep -q "^$SERVER_GROUP:"; then + echo "..ERROR creating system group. Aborting installation." + exit 1 + fi + 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 + if ! getent passwd | grep -q "^$SERVER_USER:"; then + echo "..ERROR creating system user. Aborting installation." + exit 1 + fi + 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 could abort + # the installation (like in this example) or ask the administrator. + # Using a non-system user as the one in our package could + # have unexpected consequences. + # Some packages try to prevent this kind of 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*) + FIRST_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 "$FIRST_SYSTEM_UID" ] && [ -n "$LAST_SYSTEM_UID" ]; then + if USERID=`getent passwd $SERVER_USER | cut -f 3 -d ':'`; then + if [ -n "$USERID" ]; then + if [ "$FIRST_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) + +[...] +</example> + + <sect2 id="bpp-using-sysuser"> + <heading>Using system users + +<p>In order to make use of the system user you have to make sure that the +init.d script file: + +<list> +<item>Starts the daemon dropping privileges, if the software does not +do the <manref name="setuid" section="2"> or <manref name="seteuid" +section="2"> call itself, you can use the <tt>--chuid</tt> +call of <prgn>start-stop-daemon</prgn>. + +<item>Stops the daemon only if the user id matches, you can use the +<prgn>start-stop-daemon</prgn> <tt>--user</tt> option +for this. + +<item>Does not run if either the user or the group do not exist: +<example> + if getent passwd | grep -q "^<var>server_user</var>:"; then + echo "Server user does not exist. Aborting" >&2 + exit 1 + fi + if getent group | grep -q "^<var>server_group</var>:" ; then + echo "Server group does not exist. Aborting" >&2 + exit 1 + fi +</example> + +</list> + +<p>File ownerships of files shipped by the package will need to be adjusted: + +<list> +<item>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 root and by the system group created +by the package and are mode 0640. + +<item>If the The system user generates state files (such as pidfiles) it will +need to have a directory under <tt>/var/run</tt> owned by itself. It can be +created by the package maintainers script but, since it can be wiped after a +system reboot, it should be be recreated by the init.d script since the state +directory. + +<item>If the daemon logs directly to <tt>/var/log</tt> 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 <tt>/var/log/</tt> then the directory should be owned by the +system user and rotated log files need not be changed ownership. + +</list> + + <sect2 id="bpp-removing-sysuser"> + <heading>Removing system users + +<p>If the package creates the system user it can remove it when it is +purged in its <em>postrm</em> script. This currently <em>not</em> recommended +for all situations since it has a few known +<footnote> +Some relevant threads discussing these issues include: +<url +id="http://lists.debian.org/debian-mentors/2004/10/msg00338.html">, +<url id="http://lists.debian.org/debian-devel/2004/05/msg01156.html"> +and +<url id="http://lists.debian.org/debian-devel/2005/10/msg00988.html">. +</footnote> +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). + +<p>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 <ref +id="debconf">). + +<p>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: + +<example> +case "$1" in + purge) +[...] + # Definitions for this package + [ -f "/etc/default/<var>packagename</var>" ] && . /etc/default/<var>packagename</var> + + # Sane defaults: + + [ -z "$SERVER_USER" ] && SERVER_USER=<var>server_user</var> + [ -z "$SERVER_GROUP" ] && SERVER_GROUP=<var>server_group</var> + + # 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*) + FIRST_SYSTEM_UID=`echo $LINE | cut -f2 -d '='` + ;; + LAST_SYSTEM_UID*) + LAST_SYSTEM_UID=`echo $LINE | cut -f2 -d '='` + ;; + FIRST_SYSTEM_GID*) + FIRST_SYSTEM_GID=`echo $LINE | cut -f2 -d '='` + ;; + LAST_SYSTEM_GID*) + LAST_SYSTEM_GID=`echo $LINE | cut -f2 -d '='` + ;; + *) + ;; + esac + done + fi + # Sane defaults + [ -z "$FIRST_SYSTEM_UID" ] && FIRST_SYSTEM_UID=100 + [ -z "$LAST_SYSTEM_UID" ] && LAST_SYSTEM_UID=999 + [ -z "$FIRST_SYSTEM_GID" ] && FIRST_SYSTEM_GID=100 + [ -z "$LAST_SYSTEM_GID" ] && LAST_SYSTEM_GID=999 + + # Remove system account if it is a system user + if [ -n "$FIRST_SYSTEM_UID" ] && [ -n "$LAST_SYSTEM_UID" ]; then + if USERID=`getent passwd $SERVER_USER | cut -f 3 -d ':'`; then + if [ -n "$USERID" ]; then + if [ "$FIRST_SYSTEM_UID" -le "$USERID" ] && \ + [ "$USERID" -le "$LAST_SYSTEM_UID" ]; then + echo -n "Removing $SERVER_USER system user.." + deluser --quiet $SERVER_USER || true + echo "..done" + fi + fi + fi + fi + # Remove system group if it is a system group + if [ -n "$FIRST_SYSTEM_GID" ] && [ -n "$LAST_SYSTEM_GID" ]; then + if GROUPGID=`getent group $SERVER_GROUP | cut -f 3 -d ':'`; then + if [ -n "$GROUPGID" ]; then + if [ "$FIRST_SYSTEM_GID" -le "$GROUPID" ] && \ + [ "$GROUPID" -le "$LAST_SYSTEM_GID" ]; then + echo -n "Removing $SERVER_GROUP group.." + delgroup --only-if-empty $SERVER_GROUP || true + echo "..done" + fi + fi + fi + fi +[...] +</example> + +<p>Other possibilities, are making sure the account is locked (has an invalid +password and <em>/bin/false</em> as a shell) and/or changing the GECOS field +pointing out that the account is no longer used. + +<!-- There is currently no consensus as to how any of the above should be + done in a way that would make it easy for administrators to locate + unused (but not removed) accounts --> + +</sect1> + +</sect> <sect id="bpp-config-mgmt"> <heading>Configuration management with <package>debconf</package></heading>
Attachment:
signature.asc
Description: Digital signature