Как я могу перевести прописные буквы в строчные в правиле перезаписи на веб-сервере nginx?

Мне нужно перевести адрес:

www.example.com/TEST in ---> www.example.com/test

10 ответов

Да, вам понадобится Perl. Если вы используете Ubuntu, вместо apt-get install nginx-full используйте apt-get install nginx-extras, который будет иметь встроенный модуль perl. Затем в вашем конфигурационном файле:

  http {
  ...
    # Include the perl module
    perl_modules perl/lib;
    ...
    # Define this function
    perl_set $uri_lowercase 'sub {
      my $r = shift;
      my $uri = $r->uri;
      $uri = lc($uri);
      return $uri;
    }';
    ...
    server {
    ...
      # As your first location entry, tell nginx to rewrite your uri,
      # if the path contains uppercase characters
      location ~ [A-Z] {
        rewrite ^(.*)$ $scheme://$host$uri_lowercase;
      }
    ...
location /dupa/ {
    set_by_lua $request_uri_low "return ngx.arg[1]:lower()" $request_uri;
    rewrite ^ https://$host$request_uri_low;
}

Мне удалось достичь цели с помощью встроенного Perl:

location ~ [A-Z] {
  perl 'sub { my $r = shift; $r->internal_redirect(lc($r->uri)); }';
}
location ~*^/test/ {
  return 301 http://www.example.com/test;
}

Местоположение может быть определено строкой префикса или регулярным выражением. Регулярные выражения указываются с предшествующим модификатором "~*" (для сопоставления без учета регистра) или с модификатором "~" (для сопоставления с учетом регистра).

Soruce: http://nginx.org/en/docs/http/ngx_http_core_module.html

Основываясь на ответе Адама, я использовал lua, так как он доступен на моем сервере.

set_by_lua $request_uri_low "return ngx.arg[1]:lower()" $request_uri;
if ($request_uri_low != $request_uri) {
   set $redirect_to_lower 1;
}
if (!-f $request_uri) {
    set $redirect_to_lower "${redirect_to_lower}1";
}
if ($redirect_to_lower = 11) {
    rewrite . https://$host$request_uri_low permanent;
}

Я хотел бы отметить, что большинство ответов Perl уязвимо для внедрения CRLF.

Никогда не следует использовать переменную $uri nginx в перенаправлении HTTP. Переменная $uri подлежит нормализации (подробнее), в том числе:

  • Символы в кодировке URL декодируются
  • Удаление? и строка запроса
  • Последовательные символы / заменяются одиночным /

Расшифровка URL является причиной уязвимости внедрения CRLF. В следующем примере URL-адрес добавит вредоносный заголовок в ваше перенаправление, если вы использовали переменную $uri в перенаправлении.

https://example.org/%0ASet-Cookie:MaliciousHeader:Injected

%0A декодируется в \ n \ r, и nginx добавит в заголовки следующие строки:

      Location: https://example.org
set-cookie: maliciousheader:injected

Безопасное перенаправление Perl требует замены всех символов новой строки.

      perl_set $uri_lowercase 'sub {
    my $r = shift;
    my $uri = $r->uri;
    $uri =~ s/\R//; # replace all newline characters
    $uri = lc($uri);
    return $uri;
}';

Я видел этот код по всему Интернету, и он работает. Однако он использует имя хоста, которое получает сервер nginx. В случае инфраструктуры Kubernetes это может не совпадать с тем, что использует клиент, поэтому перенаправление не только завершится неудачей, но и выдаст конфиденциальную информацию о схеме именования кластера.

Этот код работает для меня и работает немного быстрее, поскольку использует внутреннее перенаправление.

      sub {
    my $r = shift;
    my $uri = $r->uri;
    $uri =~ s/\R//; # replace all newline characters
    $uri = lc($uri);
    $r -> internal_redirect($uri)
}

Его можно использовать в файле конфигурации nginx следующим образом:

      user        nginx; # Not important for this answer, use any user you want
                   # but nginx is a sensible default.

# Load the Perl module
load_module /usr/lib/nginx/modules/ngx_http_perl_module.so;

...

http {
    server {
        # Given any location that contains an upper-case letter
        location ~ [A-Z] {
            # Lowercase it and redirect internally
            perl 'sub {
                my $r = shift;
                my $uri = $r->uri;
                $uri =~ s/\R//; # replace all newline characters
                $uri = lc($uri);
                $r -> internal_redirect($uri)
            }';
        }

        # This can be any set of rules, below is a simple one that hosts
        # static content. It will receive the lower-cased location and
        # serve it.
        location / {
            root  /usr/share/nginx/html;
            index index.html;
        }
    }
}

Мой Dockerfile начинается с этой строки и не требует дополнительных пакетов:

      FROM nginx:1.23.4-perl

В этом примере вы захотите скопировать свой статический сайт в/usr/share/nginx/htmlнапример:

      COPY nginx.conf /etc/nginx/nginx.conf
COPY src/ /usr/share/nginx/html

Перенаправление с модулем LUA.

      load_module /usr/lib/nginx/modules/ndk_http_module.so;
load_module /usr/lib/nginx/modules/ngx_http_lua_module.so;

set_by_lua $uri_lowercase "return string.lower(ngx.var.uri)";
location ~[A-Z] {
  return 301 $scheme://$http_host$uri_lowercase$is_args$args;
}

Это можно сделать только с помощью встроенного Perl.

RewriteEngine On
RewriteMap  lc int:tolower
RewriteCond %{REQUEST_URI} [A-Z]
RewriteRule (.*) ${lc:$1} [R=301,L]
Другие вопросы по тегам