Coder Social home page Coder Social logo

nginx-modules / ngx_http_hmac_secure_link_module Goto Github PK

View Code? Open in Web Editor NEW
65.0 5.0 19.0 43 KB

HMAC Secure Link module for NGINX.

License: The Unlicense

C 100.00%
nginx module hmac authentication rfc-2104 legacy openssl security hashing-algorithm hash

ngx_http_hmac_secure_link_module's Introduction

Nginx HMAC Secure Link Module

Description:

The Nginx HMAC secure link module enhances the security and functionality of the standard secure link module.
Secure token is created using secure HMAC construction with an arbitrary hash algorithm supported by OpenSSL, e.g.: blake2b512, blake2s256, gost, md4, md5, mdc2, rmd160, sha1, sha224, sha256, sha3-224, sha3-256, sha3-384, sha3-512, sha384, sha512, sha512-224, sha512-256, shake128, shake256, sm3.

Furthermore, secure token is created as described in RFC2104, that is, H(secret_key XOR opad,H(secret_key XOR ipad, message)) instead of a simple MD5(secret_key,message, expire).

Installation:

You'll need to re-compile Nginx from source to include this module.
Modify your compile of Nginx by adding the following directive (modified to suit your path of course):

Static module (built-in nginx binary)

./configure --add-module=/absolute/path/to/ngx_http_hmac_secure_link_module

Dynamic nginx module ngx_http_hmac_secure_link_module.so module

./configure --with-compat --add-dynamic-module=/absolute/path/to/ngx_http_hmac_secure_link_module

Build Nginx

make
make install

Usage:

Message to be hashed is defined by secure_link_hmac_message, secret_key is given by secure_link_hmac_secret, and hashing algorithm H is defined by secure_link_hmac_algorithm.

For improved security the timestamp in ISO 8601 the format 2017-12-08T07:54:59+00:00 (one possibility according to ISO 8601) or as Unix Timestamp should be appended to the message to be hashed.

It is possible to create links with limited lifetime. This is defined by an optional parameter. If the expiration period is zero or it is not specified, a link has the unlimited lifetime.

Configuration example for server side.

location ^~ /files/ {
    # Variable to be passed are secure token, timestamp, expiration period (optional)
    secure_link_hmac "$arg_st,$arg_ts,$arg_e";

    # Secret key
    secure_link_hmac_secret "my_secret_key";

    # Message to be verified
    secure_link_hmac_message "$uri|$arg_ts|$arg_e";

    # Cryptographic hash function to be used
    secure_link_hmac_algorithm sha256;

    # In production environment, we should not reveal to potential attacker
    # why hmac authentication has failed
    # - If the hash is incorrect then $secure_link_hmac is a NULL string.
    # - If the hash is correct but the link has already expired then $secure_link_hmac is "0".
    # - If the hash is correct and the link has not expired then $secure_link_hmac is "1".
    if ($secure_link_hmac != "1") {
        return 404;
    }

    rewrite ^/files/(.*)$ /files/$1 break;
}

Application side should use a standard hash_hmac function to generate hash, which then needs to be base64url encoded. Example in Perl below.

Variable $data contains secure token, timestamp in ISO 8601 format, and expiration period in seconds

perl_set $secure_token '
    sub {
        use Digest::SHA qw(hmac_sha256_base64);
        use POSIX qw(strftime);

        my $now = time();
        my $key = "my_very_secret_key";
        my $expire = 60;
        my $tz = strftime("%z", localtime($now));
        $tz =~ s/(\d{2})(\d{2})/$1:$2/;
        my $timestamp = strftime("%Y-%m-%dT%H:%M:%S", localtime($now)) . $tz;
        my $r = shift;
        my $data = $r->uri;
        my $digest = hmac_sha256_base64($data . "|" . $timestamp . "|" . $expire,  $key);
        $digest =~ tr(+/)(-_);
        $data = "st=" . $digest . "&ts=" . $timestamp . "&e=" . $expire;
        return $data;
    }
';

A similar function in PHP

$secret = 'my_very_secret_key';
$expire = 60;
$algo = 'sha256';
$timestamp = date('c');
$unixtimestamp = time();
$stringtosign = "/files/top_secret.pdf|{$unixtimestamp}|{$expire}";
$hashmac = base64_encode(hash_hmac($algo, $stringtosign, $secret, true));
$hashmac = strtr($hashmac, '+/', '-_');
$hashmac = str_replace('=', '', $hashmac);
$host = $_SERVER['HTTP_HOST'];
$loc = "https://{$host}/files/top_secret.pdf?st={$hashmac}&ts={$unixtimestamp}&e={$expire}";

Using Unix timestamp in Node.js

const crypto = require("crypto");
const secret = 'my_very_secret_key';
const expire = 60;
const unixTimestamp = Math.round(Date.now() / 1000.);
const stringToSign = `/files/top_secret.pdf|${unixTimestamp}|${expire}`;
const hashmac = crypto.createHmac('sha256', secret).update(stringToSign).digest('base64')
      .replace(/=/g, '')
      .replace(/\+/g, '-')
      .replace(/\//g, '_');
const loc = `https://host/files/top_secret.pdf?st=${hashmac}&ts=${unixTimestamp}&e=${expire}`;

Bash version

#!/bin/bash

SECRET="my_super_secret"
TIME_STAMP="$(date -d "today + 0 minutes" +%s)";
EXPIRES="3600"; # seconds
URL="/file/my_secret_file.txt"
ST="$URL|$TIME_STAMP|$EXPIRES"
TOKEN="$(echo -n $ST | openssl dgst -sha256 -hmac $SECRET -binary | openssl base64 | tr +/ -_ | tr -d =)"

echo "http://127.0.0.1$URL?st=$TOKEN&ts=$TIME_STAMP&e=$EXPIRES"

It is also possible to use this module with a Nginx acting as proxy server.

The string to be signed is defined in secure_link_hmac_message, the secure_link_hmac_token variable contains then a secure token to be passed to backend server.

location ^~ /backend_location/ {
    set $expire 60;

    secure_link_hmac_message "$uri|$time_iso8601|$expire";
    secure_link_hmac_secret "my_very_secret_key";
    secure_link_hmac_algorithm sha256;

    proxy_pass "http://backend_server$uri?st=$secure_link_hmac_token&ts=$time_iso8601&e=$expire";
}

Embedded Variables

  • $secure_link_hmac -
  • $secure_link_hmac_token -
  • $secure_link_hmac_expires - The lifetime of a link passed in a request.

Contributing:

Git source repositories: http://github.com/nginx-modules/ngx_http_hmac_secure_link_module/tree/master

Please feel free to fork the project at GitHub and submit pull requests or patches.

ngx_http_hmac_secure_link_module's People

Contributors

aleksey-ananin avatar bekker avatar denji avatar erfantkerfan avatar omonar avatar ununnilium avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

ngx_http_hmac_secure_link_module's Issues

Does not compile with nginx-1.10.3, x86_64

  • Darwin 16.4.0 x86_64
  • using Clang C compiler
  • clang version: 8.0.0 (clang-800.0.42.1)
  • using threads
  • using PCRE library: /Users/me/Downloads/nginx-1.10.3/pcre-8.40
  • using OpenSSL library: /Users/me/Downloads/nginx-1.10.3/openssl-1.1.0e
  • md5: using OpenSSL library
  • sha1: using OpenSSL library
  • using system zlib library

build.txt

ISO 8601 timestamp format does not work anymore because the year is interpreted as a UNIX timestamp

A timestamp passed in ISO 8601 format is interpreted as a UNIX timestamp because the year is accepted by the sscanf:

  160         /* Try if p is UNIX timestamp*/
  161         if (sscanf((char *)p, "%llu", &conv_timestamp) == 1) {
  162             timestamp = (time_t)conv_timestamp;
  163 
  164             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  165                            "secure link timestamp: \"%T\"", timestamp);
  166         } else {
                     /* Never reached with "YYYY-MM..." format because YYYY is accepted as a %llu

Consequently it's not possible anymore to use ISO 8601 format since UNIX timestamp support has been added.

There is a fix in this fork:
neokazemi@4079f29

$secure_link_hmac_expires variable not filled

During my tests, the $secure_link_hmac_expires variable value was overridden by the $secure_link_hmac_token one.

It might be due to the goto not_found when it is negative:

  228             if (expires < 0) {
  229                 goto not_found;
  230             }
  231 
  232             ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_secure_link_ctx_t));
  233             if (ctx == NULL) {
  234                 return NGX_ERROR;
  235             }
  236 
  237             ngx_http_set_ctx(r, ctx, ngx_http_hmac_secure_link_module);
  238 
  239             ctx->expires.len = value.len;
  240             ctx->expires.data = value.data;

Or to the initialization issue fixed in this fork else:

area9innovation@6ac01a2

show errors when i make nginx-1.10.0

../module/nginx-hmac-secure-link-master/ngx_http_hmac_secure_link_module.c: In function ‘ngx_http_secure_link_variable’: ../module/nginx-hmac-secure-link-master/ngx_http_hmac_secure_link_module.c:162:32: error: format ‘%d’ expects argument of type ‘int *’, but argument 3 has type ‘ngx_int_t *’ [-Werror=format=] &gmtoff_sign, &gmtoff_hour, &gmtoff_min) < 9) { ^ ../module/nginx-hmac-secure-link-master/ngx_http_hmac_secure_link_module.c:162:32: error: format ‘%d’ expects argument of type ‘int *’, but argument 4 has type ‘ngx_int_t *’ [-Werror=format=] ../module/nginx-hmac-secure-link-master/ngx_http_hmac_secure_link_module.c:162:32: error: format ‘%d’ expects argument of type ‘int *’, but argument 5 has type ‘ngx_int_t *’ [-Werror=format=] ../module/nginx-hmac-secure-link-master/ngx_http_hmac_secure_link_module.c:162:32: error: format ‘%d’ expects argument of type ‘int *’, but argument 6 has type ‘ngx_int_t *’ [-Werror=format=] ../module/nginx-hmac-secure-link-master/ngx_http_hmac_secure_link_module.c:162:32: error: format ‘%d’ expects argument of type ‘int *’, but argument 7 has type ‘ngx_int_t *’ [-Werror=format=] ../module/nginx-hmac-secure-link-master/ngx_http_hmac_secure_link_module.c:162:32: error: format ‘%d’ expects argument of type ‘int *’, but argument 8 has type ‘ngx_int_t *’ [-Werror=format=] ../module/nginx-hmac-secure-link-master/ngx_http_hmac_secure_link_module.c:162:32: error: format ‘%d’ expects argument of type ‘int *’, but argument 10 has type ‘ngx_int_t *’ [-Werror=format=] ../module/nginx-hmac-secure-link-master/ngx_http_hmac_secure_link_module.c:162:32: error: format ‘%d’ expects argument of type ‘int *’, but argument 11 has type ‘ngx_int_t *’ [-Werror=format=] cc1: all warnings being treated as errors

Won't compile on nginx-1.12.2

Using nginx-1.12.2 I get the following compile errors:

/path/to/nginx/nginx-hmac-secure-link-master/ngx_http_hmac_secure_link_module.c: In function ‘ngx_http_secure_link_variable’:
/path/to/nginx/nginx-hmac-secure-link-master/ngx_http_hmac_secure_link_module.c:160:31: error: format ‘%d’ expects argument of type ‘int *’, but argument 3 has type ‘ngx_int_t * {aka long int *}’ [-Werror=format=]
         if (sscanf((char *)p, "%d-%d-%dT%d:%d:%d%c%d:%d",
                               ^
/path/to/nginx/nginx-hmac-secure-link-master/ngx_http_hmac_secure_link_module.c:160:31: error: format ‘%d’ expects argument of type ‘int *’, but argument 4 has type ‘ngx_int_t * {aka long int *}’ [-Werror=format=]
/path/to/nginx/nginx-hmac-secure-link-master/ngx_http_hmac_secure_link_module.c:160:31: error: format ‘%d’ expects argument of type ‘int *’, but argument 5 has type ‘ngx_int_t * {aka long int *}’ [-Werror=format=]
/path/to/nginx/nginx-hmac-secure-link-master/ngx_http_hmac_secure_link_module.c:160:31: error: format ‘%d’ expects argument of type ‘int *’, but argument 6 has type ‘ngx_int_t * {aka long int *}’ [-Werror=format=]
/path/to/nginx/nginx-hmac-secure-link-master/ngx_http_hmac_secure_link_module.c:160:31: error: format ‘%d’ expects argument of type ‘int *’, but argument 7 has type ‘ngx_int_t * {aka long int *}’ [-Werror=format=]
/path/to/nginx/nginx-hmac-secure-link-master/ngx_http_hmac_secure_link_module.c:160:31: error: format ‘%d’ expects argument of type ‘int *’, but argument 8 has type ‘ngx_int_t * {aka long int *}’ [-Werror=format=]
/path/to/nginx/nginx-hmac-secure-link-master/ngx_http_hmac_secure_link_module.c:160:31: error: format ‘%d’ expects argument of type ‘int *’, but argument 10 has type ‘ngx_int_t * {aka long int *}’ [-Werror=format=]
/path/to/nginx/nginx-hmac-secure-link-master/ngx_http_hmac_secure_link_module.c:160:31: error: format ‘%d’ expects argument of type ‘int *’, but argument 11 has type ‘ngx_int_t * {aka long int *}’ [-Werror=format=]
/path/to/nginx/nginx-hmac-secure-link-master/ngx_http_hmac_secure_link_module.c: In function ‘ngx_http_secure_link_token_variable’:
/path/to/nginx/nginx-hmac-secure-link-master/ngx_http_hmac_secure_link_module.c:331:71: error: passing argument 7 of ‘HMAC’ from incompatible pointer type [-Werror=incompatible-pointer-types]
     HMAC(evp_md, key.data, key.len, value.data, value.len, hmac.data, &hmac.len);
                                                                       ^
In file included from /path/to/nginx/nginx-hmac-secure-link-master/ngx_http_hmac_secure_link_module.c:7:0:
/usr/include/openssl/hmac.h:98:16: note: expected ‘unsigned int *’ but argument is of type ‘size_t * {aka long unsigned int *}’
 unsigned char *HMAC(const EVP_MD *evp_md, const void *key, int key_len,
                ^
cc1: all warnings being treated as errors
objs/Makefile:1167: recipe for target 'objs/addon/nginx-hmac-secure-link-master/ngx_http_hmac_secure_link_module.o' failed
make[1]: *** [objs/addon/nginx-hmac-secure-link-master/ngx_http_hmac_secure_link_module.o] Error 1
make[1]: Leaving directory '/path/to/nginx/nginx-1.12.2'
Makefile:8: recipe for target 'build' failed
make: *** [build] Error 2

Add a LICENSE

Hey there,

Looking to use this module. Would love to know the associated LICENSE with this repo.

Thanks,
Aakash

Nginx crashes when trying to access $secure_link_token variable (bad value for hmac.len)

Hi,
First of all - thank you for developing and sharing this module.

When i try to use it (nginx 1.6.2, though i don't think the version is related), nginx crashes on access to $secure_link_token variable - inside the method "ngx_encode_base64url".

After some debugging it seems that hmac.len holds a bad value after call to HMAC, probably due to the casting to u_int.

I've changed (locally) the code in the method "ngx_http_secure_link_token_variable" to this:

    u_int hmac_size = 0;
    HMAC(evp_md, key.data, key.len, value.data, value.len, hmac.data, &hmac_size);
    hmac.len = hmac_size;

Which fixes the issue.

Thanks,
Shmulik

Compile Crash

./configure -- with-compat --add-dynamic-module=/opt/nginx-hmac-secure-link

cc -c -fPIC -pipe -O -W -Wall -Wpointer-arith -Wno-unused-parameter -Werror -g -I src/core -I src/event -I src/event/modules -I src/os/unix -I objs -I src/http -I src/http/modules \ -o objs/addon/nginx-hmac-secure-link/ngx_http_hmac_secure_link_module.o \ /opt/nginx-hmac-secure-link/ngx_http_hmac_secure_link_module.c /opt/nginx-hmac-secure-link/ngx_http_hmac_secure_link_module.c: In function ‘ngx_http_secure_link_variable’: /opt/nginx-hmac-secure-link/ngx_http_hmac_secure_link_module.c:127:5: error: unknown type name ‘int_t’; did you mean ‘int8_t’? int_t year, month, mday, hour, min, sec, gmtoff_hour, gmtoff_min; ^~~~~ int8_t make[1]: *** [objs/Makefile:1220: objs/addon/nginx-hmac-secure-link/ngx_http_hmac_secure_link_module.o] Error 1

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.