Can someone tell me why the nginx secure_link module expiration is not working? - nginx

I have a block using the secure_link module in an nginx conf file contained in this pastebin: https://pastebin.com/dyZmNsRe
location ^~ /file/ {
root /var/www/html;
secure_link $arg_md5,$arg_expires;
secure_link_md5 "$secure_link_expires$remote_addr$uri 6v#Q6zu3BEk4Y27Rkig7dKjW#Vd6YHV";
if ($secure_link = "") { return 403; }
if ($secure_link = "0") { return 410; }
add_header Content-Disposition "attachment; filename=$arg_name";
}
And this python script to generate the urls in this pastebin: https://pastebin.com/DdNkhmBs
import base64, sys, hashlib
import time
# Set the expiration time (in seconds)
expires = int(time.time()) + 30
# Set the IP address of the client
ip_address = "192.168.60.10"
# Set the file name
file_name = "/file/test.mp3"
text = str(expires) + ip_address + file_name + " 6v#Q6zu3BEk4Y27Rkig7dKjW#Vd6YHV"
try:
text = bytes(text, 'utf-8')
except:
pass
auth = hashlib.md5(text).digest()
query = base64.b64encode(auth)
q = str(query).replace("+", "-").replace("/", "_").replace("=", "")
q = q.replace("b'", "").replace("'", "")
print(f"http://192.168.250.83{file_name}?md5={q}&expires={expires}")
The python script works and I can generate urls that when entered into a browser, allow me to download the test.mp3 file. However, I'm under the impression that the link should expire after the expires epoch passes (in this case, 30 seconds after the url is generated). This is not what I'm seeing. I have generated urls that still working over an hour after they should have expired.
Can someone tell me what I'm missing?
Thanks!
I have done some research and have tried adding expires $arg_expires; to the nginx.conf block, with no luck. I can also change the expires query parameter or md5 and get a 403 as I expected, but urls still manage to work long after they should.

So, this issue was due to browser caching and not anything to do with nginx or Python. I tried a "working" expired link in another browser and it failed as it should. So, the real fix for this was to add the following to the nginx block:
add_header Last-Modified $arg_expires;
add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
if_modified_since off;
expires $arg_expires;
etag off;

Related

Regex returning wrong string/variable?

I'm trying to secure a HLS stream using the secure_link module in nginx. I'm doing this in two parts:
First the URL is a "SEO" friendly version, this gets rewritten to the secure_link URL which has the ?token=xxx&?expires=000.
This gets processed in the next block, and here I ONLY want to test a part of the URL (stream name in this case) and not the whole URI. I'm using a regex to get the part of the URL I need to test in a variable. But for some reason every time I execute a request I get the wrong variable here (as outputted in the debug return line) if I use the "SEO" friendly URL that is rewritten, I get the $1 from the original url, and not the $1 of the "new* (re-written) URL.
If I submit the manually rewritten request I get the correct output for that variable. So this is only happening when I'm using the first rewritten URL.
Can someone point me as to what I going on here and how I can fix this? I'm out of ideas.
Demo URL:
https://myserver.com/live/hls/PSBOBrr5bVsd3wPLMMQE7Q/1658978846/AdminTest_1080/index.m3u8
Nginx config:
location /live {
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Expose-Headers' 'Content-Length' always;
rewrite /hls/([a-zA-Z0-9_\-]*)/([0-9]*)/([a-zA-Z0-9_\-]*)/(.*)\.(ts|key|m3u8)$ /hls/$3/$4.$5?token=$1&expires=$2;
root /mnt/not-exist;
}
location ~ "/hls/([a-zA-Z0-9_\-]*)/" {
# location ~ /hls/(?<alias>[a-zA-Z0-9_]+)/ { #TRIED BOTH REGEX HERE, BOTH SAME RESULT
#internal;
secure_link $arg_token,$arg_expires;
secure_link_md5 "$host $1 $secure_link_expires $remote_addr secret";
# if ($secure_link = "") { return 403; }
# if ($secure_link = "0") { return 410; }
add_header Content-Type text/plain;
return 200 "secure_link: $host $1 $secure_link_expires $remote_addr "; # FOR DEBUGGING
}
When submitting the above example to the first location block I get the following output:
secure_link: myserver.com PSBOBrr5bVsd3wPLMMQE7Q 127.0.0.1
Which is clearly incorrectly returning another part of the URL ($1 from the first location block, not the current location block)
When using a manually crafted URL:
https://myserver.com/hls/AdminTest_1080/index.m3u8?token=token&expires=0000
I get the following (correct output):
secure_link: myserver.com AdminTest_1080 127.0.0.1
At this point I'm even considering that this might be a bug? Hoping for valuable input from the community!

nginx set expired header on files with query string

My files look like this:
/js/jquery.js?ad886e4
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|mp3) {
expires 365d;
}
But the expired headers are not set, how can i set the expired headers to files with a query string.

nginx reject request if header not present

I need nginx to reject requests if header StaticCookie is not present. I don't care about its value, I just need for it to exist.
What I came up with is this, but this doesn't work. Nginx allows requests with no headers at all.
if ($http_StaticCookie = false) {
return 403;
}
root /usr/share/asuno/www;
location ~* /css/ {
expires max;
}
location ~* /js/ {
expires max;
}
I saw this post -
Nginx: Reject request if header is not present or wrong - but it deals with defined header values. What I need is to check mere existence of the header.
I tried putting location directives inside the if clause but then nginx throws errors trying to read the config.
How can this be done?
the comment by Alexey Ten is correct, thanks.
if ($http_StaticCookie = "") { return 403; }

How to add headers in nginx only sometimes

I have a nginx proxy to a API server. The API sometimes sets the cache control header. If the API hasnt set the cache control I want nginx to override it.
How do I do that?
I think I want to do something like this, but it doesnt work.
location /api {
if ($sent_http_cache_control !~* "max-age=90") {
add_header Cache-Control no-store;
add_header Cache-Control no-cache;
add_header Cache-Control private;
}
proxy_pass $apiPath;
}
You cannot use if here, because if, being a part of the rewrite module, is evaluated at a very early stage of the request processing, way before proxy_pass is called and the header is returned from the upstream server.
One way to solve your problem is to use map directive. Variables defined with map are evaluated only when they are used, which is exactly what you need here. Sketchily, your configuration in this case would look like this:
# When the $custom_cache_control variable is being addressed
# look up the value of the Cache-Control header held in
# the $upstream_http_cache_control variable
map $upstream_http_cache_control $custom_cache_control {
# Set the $custom_cache_control variable with the original
# response header from the upstream server if it consists
# of at least one character (. is a regular expression)
"~." $upstream_http_cache_control;
# Otherwise set it with this value
default "no-store, no-cache, private";
}
server {
...
location /api {
proxy_pass $apiPath;
# Prevent sending the original response header to the client
# in order to avoid unnecessary duplication
proxy_hide_header Cache-Control;
# Evaluate and send the right header
add_header Cache-Control $custom_cache_control;
}
...
}
Awswer from Ivan Tsirulev is correct but you don't have to use regex.
Nginx uses the first parameter of map as default value automatically so you don't have to add that either.
# Get value from Http-Cache-Control header but override it when it's empty
map $upstream_http_cache_control $custom_cache_control {
'' "no-store, no-cache, private";
}
server {
...
location /api {
# Use the value from map
add_header Cache-Control $custom_cache_control;
}
...
}

NGINX secure link not working

I setup NGINX on CentOS and set config file to prevent direct access video file.
This is example code that I use.
location /videos/ {
valid_referers none blocked abccc.com;
if ($invalid_referer) {
return 403;
}
root /var/cdn/videos/;
## This must match the URI part related to the MD5 hash and expiration time.
secure_link $arg_st,$arg_e;
## The MD5 hash is built from our secret token, the URI($path in PHP) and our expiration time.
secure_link_md5 Gf1Pv52EifS1f8G9agn2k2n8a$uri$arg_e;
## If the hash is incorrect then $secure_link is a null string.
if ($secure_link = "") {
return 403;
}
## The current local time is greater than the specified expiration time.
if ($secure_link = "0") {
return 403;
}
gzip off;
gzip_static off;
mp4;
flv;
mp4_buffer_size 5M;
mp4_max_buffer_size 10M;
#mp4_limit_rate on;
#mp4_limit_rate_after 30s;
## If everything is ok $secure_link is 1.
rewrite ^/videos/(.*)$ /videos/$1 break;
}
But when restart server and test it, I still access video file in folder via
direct url and secure link.
Other wise when I try to use this configuration in localhost, it work perfectly.
What's I do wrong?

Resources