Nginx lua plugin for uploads authentication

Sometimes you want to allow your HTTP clients to upload files to a protected location without having to pass data through a secure intermediary proxy node that protect the access credentials. The clients must first request a signed URL from a third-party and then can upload the file using a HTTP POST or PUT, thus reducing latency.

For this example the signed URL has the following structure:

https://<fqdn>/<uri>?e=<timetamp>&s=<signature>

where:

  • <signature>=hmac(<password>, <uri>|<http method>|<expire timestamp>)
  • <timestamp> is the unix time designating the expiration of the URL
  • <password> is a shared secret between the HTTP server and the third party involved.

The authentication scheme is similar to the Amazon AWS signature.

The code is listed bellow (access.lua):

local expire = ngx.var.arg_e
local sign = ngx.var.arg_s
local uri = ngx.var.uri
local method = ngx.var.request_method

local path = ""
local secret = "password"

local hmac = require "resty.hmac"

 

local hmac_sha256 = hmac:new(secret, hmac.ALGOS.SHA256)
   if not hmac_sha256 then
      ngx.log(ngx.STDERR, "failed to create the hmac_sha256 object")
   return
end

 

--ngx.log(ngx.STDERR, "uri= " .. uri .. " method= " .. method .. " expire= " .. expire .. " sign= " .. sign)

if expire ~= nul and sign ~= null and uri:find("upload") and method == "PUT" then

   local digest = hmac_sha256:final(uri..method..expire, true)

   ngx.log(ngx.STDERR, "time="..os.time() .. " inputData= " .. uri.."|"..method.."|"..expire .. " sha256: " .. digest)

   if digest == sign and tonumber(expire) > os.time() then
      ngx.log(ngx.STDERR, "Upload ok")
      return ngx.OK
   end

   elseif method == "GET" then
      return ngx.OK
end

return ngx.exit(403)

And the corresponding nginx server configurations:

location /upload/ {
  lua_code_cache on;
  access_by_lua_file 'sites-available/access.lua';
  root      /var/dav;

  client_body_temp_path /var/dav/temp;
  dav_methods     PUT DELETE;
  create_full_put_path  on;
  dav_access    user:rw group:rw all:rw;
  autoindex     off;
}

The nginx server must be compiled with the openresty/lua-nginx-module.