diff --git a/README.md b/README.md index 7ade608..9dc9d00 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ 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 format should be appended to the message to be hashed. +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. @@ -111,6 +111,21 @@ $host = $_SERVER['HTTP_HOST']; $loc = "https://{$host}/files/top_secret.pdf?st={$hashmac}&ts={$timestamp}&e={$expire}"; ``` +Using Unix timestamp in Node.js + +```javascript +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}`; +``` + 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. diff --git a/ngx_http_hmac_secure_link_module.c b/ngx_http_hmac_secure_link_module.c index 32ad987..b1f97df 100644 --- a/ngx_http_hmac_secure_link_module.c +++ b/ngx_http_hmac_secure_link_module.c @@ -124,6 +124,7 @@ ngx_http_secure_link_variable(ngx_http_request_t *r, u_char hash_buf[EVP_MAX_MD_SIZE], hmac_buf[EVP_MAX_MD_SIZE]; u_int hmac_len; time_t timestamp, expires, gmtoff; + unsigned long long conv_timestamp; int year, month, mday, hour, min, sec, gmtoff_hour, gmtoff_min; char gmtoff_sign; @@ -156,50 +157,58 @@ ngx_http_secure_link_variable(ngx_http_request_t *r, "secure link timestamp: \"%*s\"", sizeof("1970-09-28T12:00:00+06:00")-1, p); - /* Parse timestamp in ISO8601 format */ - if (sscanf((char *)p, "%4d-%02d-%02dT%02d:%02d:%02d%c%02i:%02i", - (ngx_tm_year_t *) &year, (ngx_tm_mon_t *) &month, - (ngx_tm_mday_t *) &mday, (ngx_tm_hour_t *) &hour, - (ngx_tm_min_t *) &min, (ngx_tm_sec_t *) &sec, - &gmtoff_sign, &gmtoff_hour, &gmtoff_min) < 9) { - goto not_found; - } + /* Try if p is UNIX timestamp*/ + if (sscanf((char *)p, "%llu", &conv_timestamp) == 1) { + timestamp = (time_t)conv_timestamp; - /* Put February last because it has leap day */ - month -= 2; - if (month <= 0) { - month += 12; - year -= 1; - } + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "secure link timestamp: \"%T\"", timestamp); + } else { + /* Parse timestamp in ISO8601 format */ + if (sscanf((char *)p, "%4d-%02d-%02dT%02d:%02d:%02d%c%02i:%02i", + (ngx_tm_year_t *) &year, (ngx_tm_mon_t *) &month, + (ngx_tm_mday_t *) &mday, (ngx_tm_hour_t *) &hour, + (ngx_tm_min_t *) &min, (ngx_tm_sec_t *) &sec, + &gmtoff_sign, &gmtoff_hour, &gmtoff_min) < 9) { + goto not_found; + } - /* Gauss' formula for Gregorian days since March 1, 1 BC */ - /* Taken from ngx_http_parse_time.c */ - timestamp = (time_t) ( - /* days in years including leap years since March 1, 1 BC */ - 365 * year + year / 4 - year / 100 + year / 400 - /* days before the month */ - + 367 * month / 12 - 30 - /* days before the day */ - + mday - 1 - /* - * 719527 days were between March 1, 1 BC and March 1, 1970, - * 31 and 28 days were in January and February 1970 - */ - - 719527 + 31 + 28) * 86400 + hour * 3600 + min * 60 + sec; - - /* Determine the time offset with respect to GMT */ - gmtoff = 3600 * gmtoff_hour + 60 * gmtoff_min; - - if (gmtoff_sign == '+') { - timestamp -= gmtoff; - } + /* Put February last because it has leap day */ + month -= 2; + if (month <= 0) { + month += 12; + year -= 1; + } - if (gmtoff_sign == '-') { - timestamp += gmtoff; - } + /* Gauss' formula for Gregorian days since March 1, 1 BC */ + /* Taken from ngx_http_parse_time.c */ + timestamp = (time_t) ( + /* days in years including leap years since March 1, 1 BC */ + 365 * year + year / 4 - year / 100 + year / 400 + /* days before the month */ + + 367 * month / 12 - 30 + /* days before the day */ + + mday - 1 + /* + * 719527 days were between March 1, 1 BC and March 1, 1970, + * 31 and 28 days were in January and February 1970 + */ + - 719527 + 31 + 28) * 86400 + hour * 3600 + min * 60 + sec; + + /* Determine the time offset with respect to GMT */ + gmtoff = 3600 * gmtoff_hour + 60 * gmtoff_min; + + if (gmtoff_sign == '+') { + timestamp -= gmtoff; + } - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "secure link timestamp: \"%T\"", timestamp); + if (gmtoff_sign == '-') { + timestamp += gmtoff; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "secure link timestamp: \"%T\"", timestamp); + } if (timestamp <= 0) { goto not_found;