t_fischer: (tool)
Thomas Fischer ([personal profile] t_fischer) wrote in [community profile] linux4all2012-02-25 15:36

Secure WebDAV server in your home directory

This blog post shows how to setup a personal WebDAV/HTTP server which shares a directory inside your home. It is designed for local networks, but as security (SSL and username/password) is part of the configuration, you could give friends across the Internet access to the server.

The first step is to install lighttpd, an HTTP/WebDAV server. I recommend to install it through your distribution's package management system, but you can install it from source as well. Installing via package management system is the only step in this tutorial which requires superuser permissions. Take care that SSL and WebDAV is supported in your installation; Gentoo users need use flags webdav and ssl.

As the WebDAV server is meant to run in your personal directory without superuser permissions, all files for configuration have to be placed somewhere in your home directory. For the remainder of this tutorial I will use ~/lighttpd/ as an example.

There are plenty of tutorials how to create SSL certificates for an HTTPS server, so I won't go into details here. First, inside ~/lighttpd/ generate an RSA key pair using OpenSSL:

openssl genpkey -des3 -algorithm RSA -outform PEM -pkeyopt rsa_keygen_bits:2048 -out server.pem

Next, to create a certificate run the following OpenSLL command:

openssl req -new -outform PEM -out server.crt -key server.pem -keyform PEM -sha1 -x509 -days 3650

Finally, combine both files by issuing

cat server.crt >>server.pem

Now we can look into configuring lighttpd itself. For this, create a text file ~/lighttpd/lighttpd.conf. Notice the blue background color I use for all text that goes into this configuration file.

Start by defining some variables which will be used further down the config file:

var.base_dir = "/home/USERNAME/lighttpd"
var.log_dir = var.base_dir + "/log"
var.state_dir = var.base_dir + "/run"
var.conf_dir = var.base_dir + "/conf.d"

Replace USERNAME by your account name so that var.base_dir actually points to ~/lighttpd. Inside this directory, create the directories log, run, and conf.d:

mkdir log run conf.d

Tell lighttpd which modules to load. Modules mod_access and mod_accesslog are recommended in the documentation, and for WebDAV and user authentication include the respective modules.

server.modules = (
  "mod_access",
  "mod_accesslog",
  "mod_auth",
  "mod_webdav"
)

SSL seems to get built-in during compile time, so that no extra module is necessary. If not in your case, include mod_ssl.

Now we can continue with some basic configuration such as port numbers and which directory to share. Non-privileged users have to use port numbers 1024 and higher.

server.port = 5678
server.use-ipv6 = "disable"
server.document-root = "/home/USERNAME/Photos"
server.pid-file = var.state_dir + "/lighttpd.pid"
accesslog.filename = var.log_dir + "/access.log"

Files like index.html should be served automatically if a directory is accessed via HTTP (does not apply to WebDAV). If such a file is missing, list the directory instead:

dir-listing.activate = "enable"
dir-listing.encoding = "utf-8"
server.indexfiles = ("index.html", "index.htm")

To make the server using the correct mime types, i. e. downloaded files are opened with the matching viewer/editor, copy mime.conf from your official lighttpd installation into ~/lighttpd/ and include it in the configuration file:

include "mime.conf"

SSL can be activated and configured with three lines:

ssl.engine = "enable"
ssl.pemfile = var.base_dir + "/server.pem"
ssl.cipher-list = "ECDHE-RSA-AES256-SHA384:AES256-SHA256:RC4-SHA:RC4:HIGH:!MD5:!aNULL:!EDH:!AESGCM"

Now we can set up a small username-password database. As we do not aim for a large-scale system, a simple, unencrypted text file named ~/lighttpd/conf.d/lighttpd-plain.user will do. Each user will have one line in this file, where username and unencrypted password are separated by a colon (:):

falken:joshua
wagstaff:Sw0rdf1sh

To use such a simple authentication for your server, starting with the server's root directory, apply the following configuration snipplet:

auth.backend = "plain"
auth.backend.plain.userfile = var.conf_dir + "/lighttpd-plain.user"
auth.require = ( "/" =>
  (
    "method" => "digest",
    "realm" => "My Photos",
    "require" => "user=falken|user=wagstaff"
  )
)

You have to explictly enumerate which users may get access; the user names have to be the same as in ~/lighttpd/conf.d/lighttpd-plain.user.

So far, the setup implements a normal HTTP server, secured using a home-made SSL certificate and a simple username/password authentication. But as promised, we will add WebDAV support as well:

webdav.activate = "enable"
webdav.is-readonly = "enable"

This configuration makes the WebDAV server read-only by default. You can allow write access on a per-directory or per-file basis such as /incoming using regular expressions:

$HTTP["url"] =~ "^/incoming($|/)" {
  webdav.is-readonly = "disable"
}

If you fear that users of your HTTP/WebDAV server will steal all you bandwidth, you can apply traffic shaping:

server.kbytes-per-second = 512
connection.kbytes-per-second = 512

lighttpd allows you to test a configuration before going live with it. Running

lighttpd -f ~/lighttpd/lighttpd.conf -t

should print out

Syntax OK

Now you can go live with your server, simply by running the same command as above but by omitting the -t switch. When you start the server, you have to enter the password you used while creating the SSL certificate. The server will go into background by default (and become a daemon); to prevent this, used the switch -D. To stop the server once it is a daemon, you have to kill its process. For non-daemonized servers, pressing Ctrl+C does the trick.

To create accounts your friends to use your server, simply add a username/password combination into ~/lighttpd/conf.d/lighttpd-plain.user and add their usernames into the auth.require field. Your friends should get from you the username, the password, and, as retrieved by the following OpenSSL commands, the SSL certificate's serial number as well as SHA1 and MD5 hashes:

openssl x509 -in server.pem -noout -serial
openssl x509 -in server.pem -noout -fingerprint -sha1
openssl x509 -in server.pem -noout -fingerprint -md5

To avoid man-in-the-middle attacks, those credentials should be passed in person and in writing (handwriting preferred, printers store print jobs).