How to Deny Access to Dokuwiki Login Page via a Cookie

Dokuwiki is great, and I have found it really useful. The only thing I don’t like is how I can’t block bots from trying to break into the login page. They can try to log in as much as they want. It’s annoying and can allow them to eat up resources.

So let’s stop that.

Now, we could make a plugin that will block login attempts after so many tries. But let’s just keep it simple by making a visitor have a cookie to access the login page.

Back ye feinds!

The method I will show here will use some .htaccess rules to both create the cookie and block those that don’t have it. You can modify these rules to use it with nginx or other webservers.

Let me show you how it’s done. Those who are in a rush can browse own to ‘The script’ and get the script that will create all the needed rules.

Blocking the access

These examples are for showing how it works. The actual lines that you’ll copy in are in the Script section.

Here we block access to the login page. The first two lines say only to use this rule on the login or registration pages. I suppose you could add more pages to it, if you wanted.

It’s the third line that requires a specific cookie, or access will be blocked in the fourth line.

RewriteCond %{QUERY_STRING} ^(.*)?do=login(.*)$ [OR]
RewriteCond %{QUERY_STRING} ^(.*)?do=register(.*)$
RewriteCond %{HTTP_COOKIE} !^.*access_login=secret_code.*$ [NC]
RewriteRule ^(.*)$ - [F,L]

And here’s a simple nginx example:

location / {
  if ($query_string ~ "^(.*)?do=login(.*)$"){
    return 403; 
  }
  if ($query_string ~ "^(.*)?do=register(.*)$"){
    return 403; 
  }
}

If you try to access the page, you’ll get a page like this if you try to access the login page:

image-center

Or if you wanted, you could redirect them to the home page:

RewriteCond %{HTTP_COOKIE} !^.*access_login=secret_code.*$ [NC]
RewriteRule .* / [NC,L]

The .htaccess file under Apache and Nginx have the ability to tell the web server to create a cookie if a specific page is accessed. We will use that here. In the following example, if the page http://www.example.com/get_access_code is accessed, a cookie named access_login with the content secret_code is created. It is valid for 1209600 seconds (two weeks) and is valid for anything under the / path. We could change that to /wiki if Dokuwiki was under the /wiki subdirectory.

RewriteRule ^get_access_code$ - [co=access_login=secret_code:.example.com:1209600:/]

You could change that to use a random url:

RewriteRule ^get_access_code_748394584$ - [co=access_login=secret_code:.example.com:1209600:/]

Or if the site is in the wiki sub directory

RewriteRule ^wiki/get_access_code$ - [co=access_login=secret_code:.example.com:1209600:/wiki]

In these examples the cookie was good for two weeks. We can change that to one hour:

RewriteRule ^get_access_code$ - [co=access_login=secret_code:.example.com:3600:/]

And for Nginx:

location ~* (^/get_access_code/) {
     add_header Set-Cookie "access_login=secret_code:.example.com:1209600:/";
}

How to use it

There are many ways to use this method. One way is to memorize your access link, and just type it into your browser before you go to your login page. Another is to put the link on your site somewhere, and click it. Or you can even make the link the same as a page, so the access cookie will be automatically loaded when the page is loaded.

There are lots of ways, and I will leave this up to you.

The Script

Now that you know the parts, here’s a script that will make the code. I wrote it to make it easier. You can edit the resulting .htaccess (or Nginx) code according to your heart’s desire.

To use it, copy the code into a file called dw-gen (you can name it whatever you want, but this will make the examples simpler). Make sure you make it executable:

chmod +x ./dw-gen

Then in a terminal, whose working directory is the same as dw-gen, you can run the following commands to see the needed rules. The format is:

./dw-gen  <site.name> [ your own url ] [ timeout in seconds ] [ directory ]

The ‘<>’ means arguments that are required. The ‘[]’ means optional.

The simplest example is it just specify your site. Here’s an example of using my old site www.mattfiddles.com. It will generate a random url, and use the default timeout.

./dw-gen mattfiddles.com

Show rules to add for that site, but using our own url, say my_secret_access_link:

./dw-gen mattfiddles.com my_secret_access_link

Now we can go to http://www.mattfiddles.com/my_secret_access_link

To show the rules for that site, but this time with a random link, but only make the cookie valid for a day:

./dw-gen mattfiddles.com '' 86400

And to specify a subdirectory, use:

./dw-gen mattfiddles.com '' '' /wiki

To get Rules for Nginx:

./dw-gen mattfiddles.com '' '' '' nginx

And for a site in a subdirectory and a timeout:

./dw-gen mattfiddles.com my_secret_link 3600 /wiki nginx

Yes, it’s a simple script, with simple arguments. I worried about it being compatible on other’s systems. Eventually I may write a javascript here to generate the rules on this page instead. To see some more help run:

./dw-gen -h

After you generate the rules, you can copy and paste the rules into your .htaccess/http.conf (Apache) or your site’s Nginx config file as needed.

Here is the script:

#!/bin/bash

# Script to show .htaccess rules to create and require a cookie to access login page on a Dokuwiki site
# Copyright Matt Bagley under the GPL 2.

# show help if requested
if [ -z "$1" ] || [ "$1" == "-h" ] || [ "$1" == "--help" ] ; then 
  cat <<EOF

Script to show .htaccess rules to create and require 
cookie to access login page on a Dokuwiki site

Note: only use the actual domain name.
- If your site is www.example.com, just put example.com
- If your site is dev.home.example.com, use home.example.com

You can also specify your own url (url only, not domain) 
as the second argument. (Use '' as the second argument if you
want a random url, but also want to specify a access cookie timeout)

You can also specify how long the access cookie is good for 
as the third argument. By default it's two weeks ( 1209600 ).

To set a subdirectory, specify that as the fourth argument.
Rules are for Apache. For Nginx, specify 'nginx' as fifth argument.

Usage: $0 <site.name> [ your own url ] [ timeout in seconds ] [ directory ]

EOF
  exit
fi

# get the site's url.
site="$1"
url=$2
timeout=${3:-1209600}
dir=$4
nginx=$5

# function to get random strings
function __random_string() {
  # default 
  length=20
  [[ -n "$1" ]] && length=$1
  
  # first method
  rand_string="$(tr -dc A-Za-z0-9_ < /dev/urandom | head -c $length | xargs)"
  
  # second method
  if [[ -z "$rand_string" || ${#rand_string} -lt $length ]] ; then
    rand_string="$(cat /dev/urandom | base64 -w 0 | head -c$length | sed 's/[\/\+\s \n\r]/_/g')"
  fi
  
  # if we did not get one, let the user know
  if [[ -z "$rand_string" || ${#rand_string} -lt $length ]] ; then
    echo "I was not able to get a random string. Exiting."
    exit 1
  fi
}

__random_string
cookie_url_path_code=$rand_string
__random_string
cookie_name_code=$rand_string
__random_string
cookie_body_code=$rand_string

[ -z "$url" ] && url="get_access_code_$cookie_url_path_code"
if [ -n "$dir" ] ; then
  dir="$(echo $dir | sed 's/^\///g')"
  url="$dir/$url"
fi

if [ -z "$nginx" ] ; then

cat <<EOF_APACHE
# copy and paste the following in your site\'s main .htaccess file:

### Section to create and require a cookie to access login page of dokuwiki ###

# Require cookie to access login page
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{QUERY_STRING} ^(.*)?do=login(.*)$ [OR]
RewriteCond %{QUERY_STRING} ^(.*)?do=register(.*)\$
RewriteCond %{HTTP_COOKIE} !^.*access_login_$cookie_name_code=code_$cookie_body_code.*\$ [NC]
RewriteRule ^(.*)\$ - [F,L]
</IfModule>

# Get cookie here:
RewriteRule ^$url\$ - [co=access_login_$cookie_name_code=code_$cookie_body_code:.$site:$timeout:/$dir]

# Your secret url is $site/$url

### End Section to create and require a cookie to access login page of dokuwiki ###
EOF_APACHE

else  

#Nginx section

cat <<EOF_NGINX
# copy and paste the following into your site's nginx config file:

### Section to create and require a cookie to access login page of dokuwiki ###
### Note that this is BETA and may have issues ###

location ~* (^/$url/) {
     add_header Set-Cookie "co=access_login_$cookie_name_code=code_$cookie_body_code:.$site:$timeout:/$dir";
}

location /$dir {
  if ($query_string ~ "^(.*)?do=login(.*)$"){
    return 403; 
  }
  if ($query_string ~ "^(.*)?do=register(.*)$"){
    return 403; 
  }
}

# Your secret url is $site/$url

### End Section to create and require a cookie to access login page of dokuwiki ###
EOF_NGINX
  
fi

Sources:

Apache Cookies and Rewrites

Nginx Config converter

Set Nginx Cookies

Nginx Rules Explanation