2

How would I best filter traffic based on the request URI? What I'd like to do is limit access to the script some-script.php when only a certain argument list is given. For instance, allow everyone to reach user_info with associated user_id value, but deny everyone access to action=admin_login unless their IP address is on the LAN.

I know if is evil and allow all won't work as shown below but I can't seem to find what I'm wanting to do.

location ~* /live/some-script\.php {

   // allow "?action=user_info&user_id=[0-9]{1,6}"
   if ($request_uri ~* "action=bwg_frontend_data" ) {
      allow all;
   }

  // deny everyone access to "?action=admin_login", but allow 192.168.100.0/24
  if ($request_uri ~* "?action=admin_login.*")
  {
      allow from 192.168.100.0/24;
  }

  return 403;
}
Server Fault
  • 3,714
  • 12
  • 54
  • 89

1 Answers1

3

What you are trying to match is not the $request_uri, but the $query_string.

$request_uri in your case is /live/some-script.php , while $args is everything after ? (easy way to explain it to simplify this). I will be leaving the links on where you can be helped on what you want, as I can't comment your post because I have not enough reputation.

For matching the querystring:

https://gist.github.com/psd/3884613

Nginx - Redirect based on query string parameters

There is also another way with custom errors, but I kinda don't like it( you can use it if you want, it's a personal opinion):

Can nginx location blocks match a URL query string?

map $query_string $is_admin {
    ~ action=admin_login.* 1; # admin = 1
}
map $query_string $is_user {
    ~ action=bwg_frontend_data 1; #admin = 1
}
#default is empty, so it will not match the "if below".

Then inside your server code, you match $is_admin and $is_user with an if.

location ~* /live/some-script\.php {

   // allow "?action=user_info&user_id=[0-9]{1,6}"
   if ($is_user) {
      allow all;
   }

  // deny everyone access to "?action=admin_login", but allow 192.168.100.0/24
  if ($is_admin)
  {
      allow from 192.168.100.0/24;
      deny_all; #deny anyone but the allowed ones = https://support.hypernode.com/knowledgebase/blocking-allowing-ip-addresses-in-nginx/
  }

  return 403;
}

I'm just giving you the theoretical way of doing it, as I can't see your whole config, just comment if it's right or if it's not, so I can edit it adapting it on what you want. I hope it's what you are asking for.

flaixman
  • 211
  • 1
  • 4
  • Thanks, that's awesome. I had to table that project yesterda but when I get back to it I'll post results. – Server Fault Jan 08 '19 at 19:10
  • 1
    I would use `$arg_action` for the matching instead of `query_string`. Then nginx will extract the argument value and the `map` can be simpler. – Tero Kilkanen Jan 08 '19 at 22:23
  • I'm having trouble adding the `map{}` in my config. Does this configuration item need to be added in a specific config section? The file in my post above is actually in an "include" file which gets pulled in from the `server` section in `sites-enabled/site.ssl`. – Server Fault Jan 18 '19 at 18:16
  • Think I got it working. Not sure if it's the right way to go, but added an `http.d/request_maps.conf` directory/file and included it in the nginx `http` section. This seems to pull it in the correct way. I want minimal edits in `nginx.conf` so ubuntu upgrades don't whack all my changes. – Server Fault Jan 18 '19 at 18:46
  • in the location directive, I can define a `return 410` in the `if` block, but not `allow all`. Does this have something to do with the include location as well? tried moving the include into the `http` block but then it was upset with the `location` directive. – Server Fault Jan 18 '19 at 19:31