Enforce specific referer header using nginx directives.

This is a follow-up to the earlier blog post on how to stop referral spam using Nginx.

This protection can be easily circumvented, so look at it as a tiny part of a more prominent solution.

I will require the referer header and ensure that it comes from example.org domain.

First solution

The easiest solution is to use valid_referers directive to define referer whitelist.

server {
        listen 80 default_server;

        root /var/www/html;

        index index.html index.htm index.nginx-debian.html;

        server_name _;

        valid_referers server_names
            *.example.org
            example.org;

        if ($invalid_referer) {                                                                                                               
            return 403;                                                                                                                         
        }

        location / {
                try_files $uri $uri/ =404;
        }
}

example.org will return 200 OK.

$ curl -I -H "Referer: https://example.org" http://127.0.0.1
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Mon, 17 Aug 2020 21:29:16 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Sun, 16 Aug 2020 11:42:58 GMT
Connection: keep-alive
ETag: "5f391bc2-264"
Accept-Ranges: bytes

<a href="http://www.example.org" rel="nofollow">http://www.example.org</a> will return 200 OK.

$ curl -I -H "Referer: https://www.example.org" http://127.0.0.1
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Mon, 17 Aug 2020 21:30:06 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Sun, 16 Aug 2020 11:42:58 GMT
Connection: keep-alive
ETag: "5f391bc2-264"
Accept-Ranges: bytes

<a href="http://www.example.com" rel="nofollow">http://www.example.com</a> will return 403 Forbidden.

$ curl -I -H "Referer: https://www.example.com" http://127.0.0.1
HTTP/1.1 403 Forbidden
Server: nginx/1.18.0 (Ubuntu)
Date: Mon, 17 Aug 2020 21:31:20 GMT
Content-Type: text/html
Content-Length: 162
Connection: keep-alive

Missing referer header will return 403 Forbidden.

$ curl -I http://127.0.0.1
HTTP/1.1 403 Forbidden
Server: nginx/1.18.0 (Ubuntu)
Date: Mon, 17 Aug 2020 21:32:13 GMT
Content-Type: text/html
Content-Length: 162
Connection: keep-alive

Second solution

Create referer whitelist using /etc/nginx/conf.d/referer_whitelist.conf configuration file that will contain whitelisted_referer variable
whose value depends on the supplied http referer.

map $http_referer $whitelisted_referer {
  hostnames;

  "example\.org"             0; # accept   example.org
  "~*.example\.org"          0; # accept *.example.org
  default                    1; # do not accept no referer or any other referer
}

Site configuration got simpler, but the first one is a more desirable solution, but it all depends on your requirements.

server {
        listen 80 default_server;

        root /var/www/html;

        index index.html index.htm index.nginx-debian.html;

        server_name _;

        if ($whitelisted_referer) {
          return 403;
        }
 
        location / {
                try_files $uri $uri/ =404;
        }
}

example.org will return 200 OK.

$ curl -I -H "Referer: https://example.org" http://127.0.0.1
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Mon, 17 Aug 2020 21:42:47 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Sun, 16 Aug 2020 11:42:58 GMT
Connection: keep-alive
ETag: "5f391bc2-264"
Accept-Ranges: bytes

<a href="http://www.example.org" rel="nofollow">http://www.example.org</a> will return 200 OK.

$ curl -I -H "Referer: https://www.example.org" http://127.0.0.1
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Mon, 17 Aug 2020 21:42:58 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Sun, 16 Aug 2020 11:42:58 GMT
Connection: keep-alive
ETag: "5f391bc2-264"
Accept-Ranges: bytes

<a href="http://www.example.com" rel="nofollow">http://www.example.com</a> will return 403 Forbidden.

$ curl -I -H "Referer: https://www.example.com" http://127.0.0.1
HTTP/1.1 403 Forbidden
Server: nginx/1.18.0 (Ubuntu)
Date: Mon, 17 Aug 2020 21:42:30 GMT
Content-Type: text/html
Content-Length: 162
Connection: keep-alive

Missing referer header will return 403 Forbidden.

$ curl -I http://127.0.0.1
HTTP/1.1 403 Forbidden
Server: nginx/1.18.0 (Ubuntu)
Date: Mon, 17 Aug 2020 21:43:19 GMT
Content-Type: text/html
Content-Length: 162
Connection: keep-alive

References

Module ngx_http_map_module

Module ngx_http_referer_module

ko-fi