通常情况下,文件可以通过以下链接进行访问:
http://example.com/cats/cat1.zip
我想对路径名(/cats/cat1.zip)进行编码/加密,以使链接在未经编码/加密的情况下无法访问,但在对路径名进行编码/加密后可访问:
http://example.com/Y2F0cy9jYXQxLnppcAo=
上述使用了base64编码仅为简单起见,但我更希望进行加密。我该如何做?需要编写自定义模块吗?
通常情况下,文件可以通过以下链接进行访问:
http://example.com/cats/cat1.zip
我想对路径名(/cats/cat1.zip)进行编码/加密,以使链接在未经编码/加密的情况下无法访问,但在对路径名进行编码/加密后可访问:
http://example.com/Y2F0cy9jYXQxLnppcAo=
上述使用了base64编码仅为简单起见,但我更希望进行加密。我该如何做?需要编写自定义模块吗?
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哈希值:
cat1.zip
secure_link_secret
指令的参数,在这种情况下为yoursecretkey
以上示例还假设通过加密URL可访问的文件存储在/path/to/secret/files/secure
目录中。
此外,使用ngx_http_secure_link_module
模块用secure_link
和secure_link_md5
指令更灵活、但也更复杂,可以通过IP地址限制URL访问,定义URL的过期时间等。
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是可访问的(正确加密),则您正在发送文件进行下载,但是如果您需要执行其他操作,则相同的逻辑也适用。 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;
}
考虑使用像OpenResty与Lua的东西。
Lua在nginx中几乎可以实现您想要的所有功能。
==== 更新 ====
现在我们有 njs
https://nginx.org/en/docs/njs/ ,它是用于nginx的JavaScript,几乎可以做任何事情。
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 …;
}
以上方法采用了“微服务”架构,即您的解密服务的唯一工作是执行解密和访问控制,而将文件的正确提供和以最高效的方式通过内部特殊处理的X-Accel-Redirect
HTTP响应头由nginx来保证。
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)。