Nginx configuration directive location priority and security issues

  • 2020-05-07 20:53:09
  • OfStack

Recently I have been doing the location configuration and encountered the problem of priority level (there may be security risks if the configuration is not correct). The following is my personal learning experience.

1.location's matching card
1. Equal to PI: =
Equal to PI card is equal sign, the characteristics can be summarized into two points:
An exact match
Regular expressions are not supported
2. Null match
The empty match character is characterized by:
Matches URI that starts with the specified pattern
Regular expressions are not supported
3. Regular matching: ~
A regular match is a match that can use regular expressions. But it's important to note that 1 generally means:
Case-sensitive regular matching
While ~* means:
Case-insensitive regular matching
But for some case-insensitive operating systems, there is no difference. The other one is ^~, which represents a regular match that starts with the specified pattern.

4. Internal accessor: @
1 is generally used for error pages, etc., which will not be discussed for the time being.

2. Match priority
1.=
2. Empty matching card, when exact matching is met
3.^~
4. ~ or ~ *
5. An empty match that satisfies the match at the beginning of the specified pattern
That's a little abstract, but let's look at an example.

2.1 is equal to the null match when the match matches exactly

Take a look at the following example (using the Hello World module we completed 1 time ago) :


location /poechant {
    hello_world no1;
}
location = /poechant {
    hello_world no2;
}

If our request is http: / / my domian/poechant, we found that both location URI match with request, according to our priority order at this moment, the first is an exact match of empty clause, the second is equal to the clause, so a second priority, namely should output:

hello_world, no2
It also indicates that Nginx's locatoin is not matched in the order in which it is written in the configuration file.

2.2 empty match and regular match ^~ when matching exactly

In the following example, they both start to match exactly, even this regular match is an exact match.


location ^~ ^/poechant$ {
    hello_world no1;
}
location /poechant {
    hello_world no2;
}

Which one does it match? If you test 1, you will get:

hello_world, no2
This is consistent with the priority order we mentioned above.
2.3 other examples of matching priority comparisons
slightly


3. Practical experience summary

1. Priority of location matching (from practice summary)
(location =) > (location full path > ) > (location ^~ path) > (location ~* regular) > (location path)
As long as it matches, everything else is ignored, and we go back to the change match.
Test this with the following example:

 
#1    
location / {
   return 500;
}
#2
location /a/ {
    return 404;
}
#3
location ~* \.jpg$ {
    return 403;
}
#4
location ^~ /a/ {
    return 402;
}
#5
location  /a/1.jpg {
    return 401;
}
#6
location = /a/1.jpg {
    return 400;
}

Note: when testing, you should comment out all #2, or you will think #2 is exactly the same as #4. Prompt: repeat configuration, as shown below


D:\nginx-0.8.7>nginx -s reload
[emerg]: duplicate location "/a/" in D:\nginx-0.8.7/conf/nginx.conf:53

Through test: every time is access: http: / / localhost: 9999 / a / 1. jpg (in windows installation test, then port is 9999) file a / 1. jpg doesn't exist. The key is to test to see how the page returns.

a. Configure the result of the request with the above

400 Bad Request
--------------------------------------------------------------------------------
nginx/0.8.7

As you can see from the test, the highest priority is: = sign. It's going to match first.
b. Next we block #6 as follows:
#6
#    location = /a/1.jpg {
#        return 400;
#    }

Then reload configuration: D:\nginx-0.8.7 > nginx - s reload   and access: http: / / localhost: 9999 / a / 1. jpg, returned the following results:


401 Authorization Required
--------------------------------------------------------------------------------
nginx/0.8.7

Conclusion: from this test, it is found that in the absence of "=", direct access to the full path after location is the preferred match. Through test found that if the: location a / 1. jpg    : location a / 1 \. jpg
From this point, it can be inferred that the nginx match priority is: website path, and the priority without regular expression.

c. The same test blocks #5 as follows: comment and reload as above.
Access: http: / / localhost: 9999 / a / 1. jpg returns the following result.


402 Payment Required
--------------------------------------------------------------------------------
nginx/0.8.7

Conclusion: through this test, it can be concluded that: location ^~ priority is higher than location ~* priority, where: ^~ is mainly followed by the path.

c. The same test blocks #4 as follows: comment and reload as above.
Access: http: / / localhost: 9999 / a / 1. jpg returns the following result.


403 Forbidden
--------------------------------------------------------------------------------
nginx/0.8.7

Conclusion: from the above comparison, regular precedence path matching without any match character

d. The same test blocks #3 as follows: comment and reload.
Access: http: / / localhost: 9999 / a / 1. jpg returns the following result.

404 Not Found
--------------------------------------------------------------------------------
nginx/0.8.7

Conclusion: the interesting thing is that: /a/ and/  should be the same type of matching expression, you can get from it, the matching order is, match the path from the right, you can guess the shape is like character by character, which first matches to, which is the first. Thus: /a/ takes precedence over /.


The above test is the result of my test. The priority level is the above rule. In practice we often make mistakes in writing. I still remember some time ago: the security team after the 1980s exposed nginx vulnerability. Actually, I don't think it can be considered as nginx vulnerability. In fact, with the above priority, we may also make a fatal error frequently in configuration.


# Here are some random examples, which may vary from person to person 
# Suppose the site is: /home/www/html/ Directory, all of them php  And upload files are under this directory. 
location ~* \.php$ {
    proxy_pass http://www.a.com; 
}
location  /upload/ {
    alias   /home/www/html/upload/;
}

Moreover, this upload directory is a static directory, and we think that all the following files cannot be executed, including the php files.
If there is user access: http: / / www a. com upload / 1. css, can directly show the css, however, if a user access: http: / / www a. com upload / 1. php   similar files, as mentioned above, the actual match: ~ * \. php $ . upload is executed below.
From this, we found one problem that actually did not meet our requirements. Static directory under the file 1 sample executed. This is a little bit of a hassle. Once there is a bug in php, someone else has an php. We still think that our configuration is ok. Feel very safe, lack is opened 1 door by others in imperceptible.

So how do we modify it?


location ~* \.php$ {
    proxy_pass http://www.a.com; 
}
location ^~ /upload/ {
    alias   /home/www/html/upload/;
}

Yes, it must be used: "^~", so is not already safe. If you visit again next: http: / / www a. com upload / 1. php   you will find that showed this code in the source code. This is something we don't want to see anymore. 1 section shows the source code in each search engine, it is easy to search through all the special keywords to change the file.
So how do we configure secure storage directories? Yes, you've got it: limit the special file types allowed.


location ~* \.php$ {
    proxy_pass http://www.a.com; 
}
location ^~ /upload/ {
  if ($request_filename ! ~* \.(jpg|jpeg|gif|png|swf|zip|rar|txt)$) {
  return 403;
    }
    alias   /home/www/html/upload/;
}

As long as not to meet the above extension file, the automatic prompt: 403 can not access, there can avoid the source code display.
We have just learned from the match result that the match of the same level without any match character is based on the right. So, if you use regular expressions, how do they match?
The test is as follows :(new configuration file, server included)


    location ~* \.jpg$ {
            return 402;
    }
    location ~* 1\.jpg$ {
            return 403;
    }

The results are as follows:


402 Payment Required
--------------------------------------------------------------------------------
nginx/0.8.7

Looks like it's returning: one above 402. In theory, 1.jpg configuration is more accurate than.jpg configuration. Let's test again:


location ~* 1\.jpg$ {
            return 403;
    }
    location ~* \.jpg$ {
            return 402;
    }

The return result is:


403 Forbidden
--------------------------------------------------------------------------------
nginx/0.8.7

Haha, on the contrary, it seems that my inference is correct, if all are regular, all can match, in the order of configuration files appear, who comes first and who comes first. 1 tone said, do not know friend you, understand my train of thought? There are many, many comparisons, and you can test them one by one. Familiarity with location configuration is a prerequisite for proficiency in nginx. Because nginx is too flexible and too popular. The above problem, perhaps friend you, will encounter. I hope it helped you.


Related articles: