I made react website, that request a remote http API (managed by a third party). My website is using https with a valide certificate.
- The third party API is "secured" by a simple GET param in the URL , "?key=XXXX" . to check if we can access the endpoint.
- The third party API has CORS
To be able to request the http remote API I made a nginx reverse proxy . With extra header to allow CORS. And to secure a little bit more I added JWT Token verification .
All is working fine , if the Header Authorization Bearer with token is invalid or unset i cannot access the third party api. nginx is blocking me.
But as soon as I provide a valid Authorization Header once , any further request will PASS. the token is not checked anymore , even if i make the request from a different device with different IP.
How to check the token for every single request i make
Here is my nginx conf
server {
listen 443 ssl http2;
ssl_certificate /etc/letsencrypt/live/mydomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mydomain.com/privkey.pem;
location / {
default_type application/json;
return 200 '{"message": "Endpoint is required"}';
}
location ^~ /api/ {
include jwt.conf;
include headers.conf;
set $args $args&key={KEY};
proxy_pass http://www.third-party.com/api/;
}
}
Here is my jwt.conf file , I am using the openresty lua-nginx-module
access_by_lua_block {
local jwt = require "resty.jwt"
local jwt_obj = jwt:verify("{SECRET}", token, claim_spec)
local auth_header = ngx.var.http_Authorization
if auth_header then
_, _, token = string.find(auth_header, "Bearer%s (. )")
end
if token == nil then
ngx.status = ngx.HTTP_UNAUTHORIZED
ngx.header.content_type = "application/json; charset=utf-8"
ngx.say("{\"error\": \"missing JWT token or Authorization header\"}")
ngx.exit(ngx.HTTP_UNAUTHORIZED)
end
if not jwt_obj["verified"] then
ngx.status = ngx.HTTP_UNAUTHORIZED
ngx.log(ngx.WARN, jwt_obj.reason)
ngx.header.content_type = "application/json; charset=utf-8"
ngx.say("{\"error\": \"" .. jwt_obj.reason .. "\"}")
ngx.exit(ngx.HTTP_UNAUTHORIZED)
end
}
And to be complete , my headers.conf
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_redirect off;
proxy_buffers 32 16k;
proxy_busy_buffers_size 64k;
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, PUT, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
add_header 'Access-Control-Max-Age' 1728000;
return 204;
}
# Ajouter les headers de contrôle d'accès CORS
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, PUT, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Origin, X-Requested-With, Content-Type, Accept, Authorization' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
CodePudding user response:
Here:
_, _, token = string.find(auth_header, "Bearer%s (. )")
you declare token
as a global variable. It is strongly discouraged:
Note that the use of global Lua variables is strongly discouraged, as it may lead to unexpected race conditions between concurrent requests.
It explains why subsequent requests are authorized if you do not include the Authorization
header -- the token
from the initial request is "cached" in the Lua global state.
Moreover, here:
local jwt_obj = jwt:verify("{SECRET}", token, claim_spec)
you reference the token
variable before it is declared.
The correct code is something like this:
local jwt = require "resty.jwt"
local auth_header = ngx.var.http_Authorization
-- `local token` is equvalent to `local token = nil`
local token
if auth_header then
token = string.match(auth_header, "Bearer%s (. )")
end
if token == nil then
ngx.status = ngx.HTTP_UNAUTHORIZED
ngx.header.content_type = "application/json; charset=utf-8"
ngx.say("{\"error\": \"missing JWT token or Authorization header\"}")
ngx.exit(ngx.HTTP_UNAUTHORIZED)
end
-- BTW, where do the `claim_spec` come from?
local jwt_obj = jwt:verify("{SECRET}", token, claim_spec)
if not jwt_obj["verified"] then
ngx.status = ngx.HTTP_UNAUTHORIZED
ngx.log(ngx.WARN, jwt_obj.reason)
ngx.header.content_type = "application/json; charset=utf-8"
ngx.say("{\"error\": \"" .. jwt_obj.reason .. "\"}")
ngx.exit(ngx.HTTP_UNAUTHORIZED)
end