【问题标题】:Encode and decode pathname in nginx在 nginx 中编码和解码路径名
【发布时间】:2018-06-04 18:57:41
【问题描述】:

通常可以在以下位置访问文件:

http://example.com/cats/cat1.zip

我想对路径名 (/cats/cat1.zip) 进行编码/加密,以便链接无法正常访问,但在路径名加密/编码后可以访问:

http://example.com/Y2F0cy9jYXQxLnppcAo=

为了简单起见,我在上面使用 base64 编码,但更喜欢加密。我该怎么做?我必须编写自定义模块吗?

【问题讨论】:

    标签: nginx encryption configuration


    【解决方案1】:

    您可以使用Nginx rewrite rule 重写网址(从编码到未编码)。而且,要应用您的编码逻辑,您可以使用自定义函数(我使用 perl module 完成了此操作)。

    可能是这样的:

     http {
      ...
        perl_modules perl/lib;
        ...
        perl_set $uri_decode 'sub {
          my $r = shift;
          my $uri = $r->uri;
          $uri = perl_magic_to_decode_the_url;
          return $uri;
        }';
        ...
        server {
        ...
          location /your-protected-urls-regex {
            rewrite ^(.*)$ $scheme://$host$uri_decode;
          }
    

    【讨论】:

      【解决方案2】:

      如果您唯一关心的是限制对某些 URL 的访问,您可以查看 this post on Securing URLsSecure Link Module in Nginx

      它提供了相当简单的方法来保护您的文件——加密您的 URL 的最基本和最简单的方法是使用 secure_link_secret 指令:

      server {
      
          listen 80;
          server_name example.com;
      
          location /cats {
              secure_link_secret yoursecretkey;
              if ($secure_link = "") { return 403; }
      
      
              rewrite ^ /secure/$secure_link;
          }
      
      
          location /secure {
              internal;
              root /path/to/secret/files;
          }
      }
      

      访问cat1.zip 文件的URL 将是http://example.com/cats/80e2dfecb5f54513ad4e2e6217d36fd4/cat1.zip,其中80e2dfecb5f54513ad4e2e6217d36fd4 是在连接两个元素的文本字符串上计算的MD5 哈希:

      1. 哈希之后的 URL 部分,在我们的例子中是 cat1.zip
      2. secure_link_secret 指令的参数,在本例中为 yoursecretkey

      以上示例还假设通过加密 URL 访问的文件存储在 /path/to/secret/files/secure 目录中。

      此外,还有一种更灵活但也更复杂的方法,通过使用secure_linksecure_link_md5 指令来使用ngx_http_secure_link_module 模块保护URL,通过IP 地址限制URL 访问,定义过期时间网址等

      如果您需要完全隐藏您的网址(包括 cat1.zip 部分),您需要在以下各项之间做出决定:

      1. 在 Nginx 端处理加密 URL 的解密 - 编写自己的,或重用别人编写的模块
      2. 在应用程序中的某处处理加密 URL 的解密 — 基本上使用 Nginx 将加密 URL 代理到应用程序,在该应用程序中解密它们并采取相应措施,如 @cnst 上面所写。

      这两种方法各有利弊,但 IMO 后一种方法更简单、更灵活——一旦你设置了代理,你就不需要太担心 Nginx,也不需要用一些特殊的先决条件来编译它;无需使用您已经在应用程序中编写的语言编写或编译代码(除非您的应用程序包含 C、Lua 或 Perl 代码)。

      这是一个简单的 Nginx/Express 应用程序示例,您可以在其中处理应用程序中的解密。 Nginx 配置可能如下所示:

      server {
      
          listen 80;
          server_name example.com;
      
          location /cats {
              proxy_set_header Host $http_host;
              proxy_set_header X-Real-IP $remote_addr;
              proxy_set_header X-Forwarded-For $remote_addr;
              proxy_set_header X-NginX-Proxy true;
              proxy_http_version 1.1;
              proxy_set_header Upgrade $http_upgrade;
              proxy_set_header Connection "upgrade";
              proxy_pass http://127.0.0.1:8000;
          }
      
          location /path/to/secured/files {
              internal;
          }
      }
      

      在应用程序 (Node.js/Express) 方面,您可能会遇到以下情况:

      const express = require ('express');
      const app = express();
      
      app.get('/cats/:encrypted', function(req, res) {
        const encrypted = req.params.encrypted;
      
        // 
        // Your decryption logic here
        //
        const decryptedFileName = decryptionFunction(encrypted);
      
        if (decryptedFileName) {
          res.set('X-Accel-Redirect', `/path/to/secured/files/${decryptedFileName}`);
        } else {
          // return error
        }
      });
      
      
      app.listen(8000);
      

      以上示例假定受保护文件位于/path/to/secured/files 目录。它还假设如果 URL 可访问(正确加密),则您正在发送文件以供下载,但如果您需要执行其他操作,则同样的逻辑将适用。

      【讨论】:

      • 看来 echo -n 'cat1.zipyoursecretkey' | openssl md5 -hex 不会产生您提供的哈希值。你能详细说明原因吗?
      【解决方案3】:

      最简单的方法是编写一个简单的后端(例如,通过proxy_pass 进行接口)从$uri 中解密文件名,并在X-Accel-Redirect 响应标头中提供结果(这是主题到 nginx 中的 proxy_ignore_headers ),随后将在 nginx 内进行 internal 重定向(到一个不先通过后端就无法访问的位置),并提供已经是 nginx 一部分的所有优化。

      location /sec/ {
          proxy_pass http://decryptor/;
      }
      location /x-accel-redirect-here/ {
          internal;
          alias …;
      }
      

      上述方法遵循“微服务”架构,因为您的解密器服务的唯一工作是执行解密和访问控制,将其留给 nginx,以通过使用内部经过特殊处理的X-Accel-Redirect HTTP 响应头。

      【讨论】:

      【解决方案4】:

      考虑在 Lua 中使用 OpenResty 之类的东西。

      Lua 几乎可以在 nginx 中做任何你想做的事情。

      https://openresty.org/

      https://github.com/openresty/

      ==== 更新 ====

      现在我们有了 njs https://nginx.org/en/docs/njs/ ,用于 nginx 的 javascript,它几乎可以做任何事情。

      【讨论】:

        【解决方案5】:

        如果有人在 Nginx 中遇到非转义查询参数的问题,这就是我在 Ubuntu 20.04 上的标准 Nginx 设置上解决它的方法(url 中的查询参数是 foo,如 https://some.domain.com/some/path?foo=some%2Fquery%2Fvalue):

          perl_modules perl/lib;
        
          perl_set $arg_foo_decoded 'sub {
            my $r = shift;
            my $arg_foo = $r->variable("arg_foo");
            $arg_foo =~ s/\+/ /ig;
            my $arg_foo_decoded = $r->unescape($arg_foo);
            return $arg_foo_decoded;
          }';
        

        然后我可以在我的location 块中使用$arg_foo_decoded 变量。它现在包含some/query/value

        编辑

        添加了一行以确保与包含编码为+ 的空格的表单值兼容(另请参阅:https://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1)。

        【讨论】:

          猜你喜欢
          • 2013-02-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-08-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多