⬆️ ⬇️

Algorithm of a choice of location in Nginx

The location selection algorithm is required to know when configuring nginx. However, the official site of nginx (for 2018) does not say a word about the selection algorithm in cases where some locations are embedded into each other, and in the articles on the Internet, incorrect algorithms are given in the root . The article will also give an example of a vulnerable config.



A special case with one level of nesting



If you are new to nginx, then you should first consider a special case without using nested locations, since the algorithm for a particular case is much simpler:



  1. First, equality (=) will be sought. It has the highest priority.
  2. Then the maximum length prefix location (() or (^ ~)) will be searched, after which it will be checked if there is a priority modifier (^ ~) on the found location, and if it exists, this location will be returned.
  3. Then regular expressions ((~) and (~ *)) will be checked from top to bottom. If it matches, the first location will be returned.
  4. Then that prefix location, which we found before, will return.


Please note that this algorithm is not applicable if there are nested locations.



General case with nested location



  1. We start from the top level.
  2. If the current level is equal (=), the search stops - this will be the result, since such a location can not have any other nested locations.
  3. Otherwise, we search the current level for the largest prefix location (() or (^ ~)).
    • If such a prefix location exists, then we make it the current level and proceed to step 2.
    • Otherwise, exit the loop.
  4. We are out of the loop. At the moment we have found the “largest” prefix location, but do not think that this is the largest of all. Example:

    ')

    location /abc { location /abcdefghi { … } } location /abcdef { … } 


    In this example, we will go to / abcdef, because at his level he overcame a shorter / abc. But in fact there are location and more.
  5. Now in the found location we are looking for the first valid regexp. When finding the search completely stops. Please note: at this point we are in fact looking for a regexp at the lowest level, and not at the top, as many might think. That is, the search for regexp comes from the bottom, not from the top (but inside one level comes from the top, not the bottom).
    • Further, if nothing is found, we go up one level and similarly we are looking for the first regexp, but this time it is only provided that the location in which we were before did not have a label (^ ~). Repeat this point until there is nowhere to go up.
    • It should be borne in mind:
      • Even if one of the levels has a label (^ ~), this does not mean that we do not lift. Lifting is always done, but if the lower level had a label (^ ~), then at the current level the search for regexps is not performed.
      • There is no possibility to disable regexp checking in the lowest level - for this you need to create another nested level. But it is possible to disable regexp checking at the zero level - for this location of the first level (which is at the zero level) it must have a label (^ ~).
  6. We made a climb on a tree, but never found a single regexp. Once regexp is not found, we return “almost the biggest” to the prefix location that was found earlier. Is done.


Also with this:





Example of a vulnerable config



 location ~ \.php$ { deny all; #      php-fpm } location /posts/ { location ~ (.*)_2x(\.[az]+)$ { try_files $uri $1$2 =404; } } 


In this config, we configured ignoring "_2x" if the file is not found. For example, nginx will try to find the file /posts/img/a_2x.png both along the specified path and along the path /posts/img/a.png. But in reality, if we request /posts/authData_2x.php, then we will get the source code of the authData.php script in the bare form. To avoid such errors, you need to know how location is handled in nginx.



Also, additional protection may be the storage of scripts in a separate directory, inaccessible from under the normal location. In this case, if our location on php for some reason does not work, the user will receive error 404, and not the source text of the script.



Location redirection



  1. If try_files does not contain the error code as the last parameter, it will be redirected to another location, since the last parameter always redirects. Please note: the error code in try_files should be written with an equal (=).
  2. index and error_page always trigger redirections to another location when triggered. Also, the redirect makes rewrite if you add the flag last to it.


Other



  1. When selecting a location, the query string that begins with the "?" Is not taken into account.


Denial of responsibility



The algorithm in the article was compiled by me on the basis of my personal observations, and not the fact that it is correct. Unfortunately, there is no official documentation, but I have not read the source code. If someone finds errors in the algorithm, please write a personal message or in the comments.

Source: https://habr.com/ru/post/348206/



All Articles