Access your servers securely with a Magic URL

It's a Kind of Magic

I've explained that two-step and fail2ban are optional components, but I should really have one mechanism locking sshd to specific IP addresses at the very least in case I make a mistake with my Magic URL config. I could easily use iptables on it's own, for example, but I need to be careful not to confuse that with my fail2ban rules. The Magic URL functionality will allow otherwise untrusted dynamic IP addresses to connect briefly over SSH to the server, so for clarity, to do so, I'll follow these steps below:

  1. Set up my .htaccess files, which means that even if my Magic URL is guessed, a username and password is needed to get access to it via a Browser (and fail2ban won't take too kindly to any failed passwords at all if it's configured correctly!).
  2. Write a script (and break it up into segments to keep it simple) to check to see if I need to act after my Magic URL has been accessed and tidy up previous SSH access entries, as well.
  3. Create a simple cron job to set the Magic URL, so it runs every minute.

Sleight of Hand

Even novice sys admins have probably heard of .htaccess files, which provide some web servers (Apache being the most popular) with some clever functionality, like cleaning up URLs or password protection of web pages. I'll create two simple files, each with just a single line, to add password protection to my chris-magic-url/ directory.

To keep my password secure I'll save the password file a level above web root (so it's not viewable by web visitors); in this case, that's /var/www. In that directory the .htpasswd file looks like this:


As you can see, my username is hack-and-defend and my password is an MD5 hash. If you're new to how this works, I must tell you about it, because it's really very clever. The password is just obfuscated characters using MD5 and written as a hash. The actual password is never saved to disk. The login process asks for a password, creates a hash of it, and simply compares it to the one saved on the disk. If it matches, I'm allowed in. You have to love intelligent security that uses such well-considered simplicity.

The next step is easy, too. At the top of the web root, I create two directories. (With some fine tuning, the two directories could become one, but I'll keep using two directories for simplicity.) The first directory is called chris-magic-url/ and the second is secret-service/. In my case, secret-service/ is the CCTV footage viewing page I mentioned. You might have an application or something precious sitting in your secret-service/ directory.

For clarity, my Magic URL will open up SSH access to any IP address, and the secret-service/ directory isn't strictly related. I thought it was worth mentioning, though, because in addition to the Magic URL functionality, you can also do what I think are pretty clever things with IP addresses and password protection with htaccess files. Here's a quick look to give you some food for thought.

You might want to improve the Magic URL functionality to let only specific IP addresses even attempt that first login via htaccess. Think about something like this example in Listing 1. You can see that not only do I ask for a password for access to my web server files, but I also have configuration in place that doesn't ask for a password if either the single IP addresss connects or the whole /24 network connects. That's very convenient.

Listing 1

.htaccess Config

AuthName "These aren't the droids you're looking for. Go about your business."
AuthUserFile /var/www/.htpasswd
AuthType Basic
<Limit GET POST>
Require valid-user
Order Deny,Allow
Deny from all
Allow from
Allow from
Satisfy Any

The clever line is Satisfy Any. Be warned that you should test this carefully before trusting it implicitly. I really like this functionality, and the nice thing about htaccess is that any changes you make to it via a script (e.g., adding a trusted IP address via Magic URL functionality) are live immediately, and no web server restarts are required.

Back to the simpler htaccess approach and the second htaccess file: I'm going to insist that everyone is asked for a password, and in this case, fail2ban will keep me safe from repetitive attacks. You'll be glad to know that the second file is straightforward too and looks like Listing 2. This time the file resides in the directory /var/www/html/chris-magic-url/ and I call the file .htaccess (see the ".htaccess Files" box).

.htaccess Files

In case you aren't aware, the prepended dot for these htaccess files not only makes them hidden files on the filesystem, but modern web servers also know not to serve these files directly to a browser (e.g., so your MD5 hash is never exposed). For example, Apache has this configuration in the apache2.conf file in my Debian jessie build:

# The following lines prevent .htaccess and .htpasswd files from being
# viewed by web clients.
<FilesMatch "^\.ht">
        Require all denied

Listing 2

A Simple .htaccess File

AuthName "You're definitely not welcome here. Move along."
AuthUserFile "/var/www/.htpasswd"
AuthType Basic
Require user hack-and-defend

I'll also put a copy of my second file (.htaccess) in my secret-service/ directory to protect my secret application (e.g., the viewing page in my case). Again, you don't need to do this to get the Magic URL functionality working, and it's optional, it's simply to give you some context for where your prized assets might live in relation to your Magic URL directory.

The only other thing I'll need inside my virtual host files for htaccess to function correctly (as it applies to my Debian jessie build and Apache version 2.4.10-10+deb8u4) is an entry in the /etc/apache2/sites-available/ virtual host entries. Within the 000-default.conf file, and the default-ssl.conf file if you're using SSL/TLS, I add the following before closing the </VirtualHost> tag:

<Directory "/var/www/html">
AllowOverride AuthConfig

Clearly, I need to alter the directory on which I am enabling password protection by editing the line:

Directory "/var/www/html"

Now I just need to tell Apache that I've made those changes, if they weren't there before, with a quick config reload as follows for Debian derivatives on systemd machines (first line) or the SysV equivalent for older versions (second line):

# systemctl reload apache2
# /etc/init.d/apache2 reload

On Red Hat derivatives, your package might be called httpd and not apache2, so use

# systemctl reload httpd
# /etc/init.d/httpd reload

for systemd and SysV systems, respectively.

After using the Bash script [5] for the first time, which I'll look at shortly, and triggering a Magic URL, a quick peek inside the /var/www/html/chris-magic-url/ directory reveals the previously unseen files, and the Magic URL directory contains:


Remember, to get the bare minimum working, you only need htaccess files in place, TCP Wrappers, the Bash script, and a cron job.

Hat Trick

It's important to note that single lines in the script could easily use iptables as opposed to TCP Wrappers. I prefer the simplicity of dealing with the /etc/hosts.allow file from TCP Wrappers for a task like this. Hopefully, it also makes it easier to follow and avoids confusion because I'm looking at fail2ban iptables entries too.

To set up TCP Wrappers for SSH, I first put a global deny in the /etc/hosts.deny file (Listing 3). This example includes a nice little trick to receive email whenever someone or something is rejected by a TCP Wrapper rule. One caveat: If this makes your server prone to denial of service attacks because someone can generate a lot of email, then disable it.

Listing 3

Receive Email on Attack

         echo "\n\
         TCP Wrappers\: Connection refused\n\
         By\: $(uname -n)\n\
         Process\: %d (pid %p)\n\
         User\: %u\n\
         Host\: %c\n\
         Date\: $(date)\n\
       " | /usr/bin/mail -s "Connection to %d blocked" chris@binnie.tld) &

The ALL:ALL is the only entry you need to deny all IP addresses for all services in that file if you don't want to receive email. Try it and see if you like the functionality. I love this feature of TCP Wrappers, because it helps me keep an eye on misconfigurations and attacks via the occasional email.

In /etc/hosts.allow you should add (comma delimited) IP addresses to which you want to allow SSH access:


I won't edit /etc/hosts.allow directly any further because the Magic URL script will take care of writing to that from now on. Be warned not to disconnect your existing SSH session, however, or you might lose remote access. Test the Magic URL set up using a virtual machine with a remote console (or one which has out-of-band access) if you don't want to risk being accidentally locked out of your server.

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy Linux Magazine

Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

comments powered by Disqus

Direct Download

Read full article as PDF:

Price $2.95


njobs Europe
Njobs Netherlands Njobs Deutschland Njobs United Kingdom Njobs Italia Njobs France Njobs Espana Njobs Poland
Njobs Austria Njobs Denmark Njobs Belgium Njobs Czech Republic Njobs Mexico Njobs India Njobs Colombia