Nginx – Block POST PUT and DELETE but allow GET from specific referrer

httpnginxrequestsweb-server

I'm using nginx and I want to block post, put and delete requests when they come from an unknown referrer.

Meaning, I have the referrer: ".example.com" and from this referrer I want to allow all GET, PUT and POST (yeah, I know thats easy to fake the referrer …), if ".example.com" is not the referrer only GET should be allowed.

All the solutions I came with don't work …

I would like to have this on the server block to make everything clean (I use a very big file with all the locations).

My first approach was:

limit_except none block server_names *.example.com {
if ($http_request != GET) {
deny all;
}

But, I cannot nest an if …

Then, I tried this:

map $http_referer $allow_referer {
default 0;
"~example.com" 1;
}
map $allow_referer $disallow_referer {
0 1;
1 "";
}

location … {

if ($invalid_referer) {
limit_except GET {
deny all;
}
}
}

Same as above.
Then, I used a config file I found on the web with some modifications :

set $cors '';

if ($http_origin ~* (https?://.*.example.com(:[0-9]+)?)) {
set $cors "true";
}

if ($request_method = 'OPTIONS') {
set $cors "${cors}options";
}

if ($request_method = 'GET') {
set $cors "${cors}get";
}

if ($request_method = 'POST') {
set $cors "${cors}post";
}

if ($request_method = 'PUT') {
set $cors "${cors}put";
}

if ($request_method = 'DELETE') {
set $cors "${cors}delete";
}

if ($cors = "trueget") {
return 200;
}

if ($cors = "truepost") {
return 403;
}

if ($cors = "trueput") {
return 403;
}

if ($cors = "truedelete") {
return 403;
}

Seems very clean but didn't work.

Is there any way to this ?

Best Answer

I added this to the server block and it works:

add_header Allow "GET, POST, PUT, DELETE, HEAD" always;
valid_referers none blocked server_names *.example.com;

if ($request_method !~ ^(GET)$ ) {
    set $req A;
    }

if ($invalid_referer) {
    set $ref "${req}A";
    }

  if ($ref = AA) {
   return 403;
   }