Nginx – Image hotlink protection using rewrite
Image hotlinking is when someone serves media stored on your server directly on their webpage – hence stealing bandwidth. It is not cool!
Nginx makes it very easy to stop image hotlink. There are several pages on the internet which talkabout it.
Requirements
- I wanted generic solution which would work for all my domains, without changing each of their configs (sites-enabled)
- Rewrite and display a different image in place of the hotlinked media
- Must play nice with Google/Other image search engines – instead of stopping hotlink always
Solution
location ~* .(gif|png|jpe?g)$ { expires 7d; add_header Pragma public; add_header Cache-Control "public, must-revalidate, proxy-revalidate";
# prevent hotlink valid_referers none blocked ~.google. ~.bing. ~.yahoo. server_names ~($host); if ($invalid_referer) { rewrite (.*) /static/images/hotlink-denied.jpg redirect; # drop the 'redirect' flag for redirect without URL change (internal rewrite) } }
# stop hotlink loop location = /static/images/hotlink-denied.jpg { }
Details
~
is used for case sensitive matching while~*
is for case insensitive matching.- nginx checks locations given by regular expression in the order listed in the configuration file – more here. This means that cache headers for media and image hotlinking prevention have to be in the same block!
location = /static/images/hotlink-denied.jpg { }
is required to prevent infinite loop that happens: Evil site requests A.jpg -> redirect request to B.jpg -> Evil site requests B.jpg -> redirect reqest to B.jpg -> … . nginx first searches for the most specific prefix location given by literal strings regardless of the listed order – more here.$host
is a variable that makes the solution generic – it will servehttps://$host/static/images/hotlink-denied.jpg
for each domain. We just need to place different image in the same path on all domains.- The rewrite module always sends 302 Found response when either: [1] rewrite flag is specified [2] or when the URL being redirected to starts with https://.
- This means that the URL shown in browser will change to the redirected URL.
- If you want an redirect without URL change (internal rewrite, with no 302), then just drop the redirect flag in the rewrite. These two links helped me learn that.
Testing
- Use the command
nginx -s reload
to reload configuration. - I used this tool to verify the changes. Always use an incognito window for this test, as your target image might already be in browser cache.
- Other way of testing is using the
curl
command, for examplecurl --referer https://www.evil.com <IMAGE_URL>
should show either indicate302
redirect, or return the anti-hotlink image, whilecurl --referer https://www.google.com <IMAGE_URL>
should return the correct image.
Source: nodotcom.org
Leave comments