Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions apisix/plugins/jwt-auth.lua
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,18 @@ local function find_consumer(conf, ctx)
return nil, nil, "failed to verify jwt"
end

-- Enforce that the JWT header's "alg" matches the consumer's configured algorithm
local expected_alg = consumer.auth_conf.algorithm or "HS256"
local token_alg = jwt.header and jwt.header.alg
if token_alg ~= expected_alg then
local err = "failed to verify jwt: algorithm mismatch, expected " .. expected_alg
if auth_utils.is_running_under_multi_auth(ctx) then
return nil, nil, err
end
core.log.warn(err)
return nil, nil, "failed to verify jwt"
end

-- Now verify the JWT signature
if not jwt:verify_signature(auth_secret) then
local err = "failed to verify jwt: signature mismatch: " .. jwt.signature
Expand Down
8 changes: 4 additions & 4 deletions t/plugin/jwt-auth-more-algo.t
Original file line number Diff line number Diff line change
Expand Up @@ -154,15 +154,15 @@ JWT token invalid: invalid header: invalid-eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9



=== TEST 6: verify token with algorithm HS256
=== TEST 6: verify token with algorithm HS384
--- request
GET /hello
--- more_headers
Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTg3OTMxODU0MX0.fNtFJnNmJgzbiYmGB0Yjvm-l6A6M4jRV1l4mnVFSYjs
Authorization: eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTg3OTMxODU0MX0.yM8L6f3cGZxKqflMJlf0DqfQVpHUxupqgM3JWETyRQ8Iag1HiRrHILEA-A2rhmEq
--- response_body
hello world
--- error_log
parsed jwt alg: HS256
parsed jwt alg: HS384



Expand Down Expand Up @@ -329,7 +329,7 @@ passed
--- request
GET /hello
--- more_headers
Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTU2Mzg3MDUwMX0.pPNVvh-TQsdDzorRwa-uuiLYiEBODscp9wv0cwD6c68
Authorization: eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTU2Mzg3MDUwMX0.SJNbFYR1qlIOD7D8aItkB9hYxdhc0d_JGaLgVjOCDOAHd8CSJuHp_R6YQniRDq8S
--- response_body
hello world

Expand Down
59 changes: 59 additions & 0 deletions t/plugin/jwt-auth.t
Original file line number Diff line number Diff line change
Expand Up @@ -1242,3 +1242,62 @@ hello world
}
--- response_body
passed



=== TEST 52: HS256 token against RS256 consumer
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
-- Set up an RS256 consumer
local code, body = t('/apisix/admin/consumers',
ngx.HTTP_PUT,
[[{
"username": "kerouac",
"plugins": {
"jwt-auth": {
"key": "user-key-rs256",
"algorithm": "RS256",
"public_key": "-----BEGIN PUBLIC KEY-----\nMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKebDxlvQMGyEesAL1r1nIJBkSdqu3Hr\n7noq/0ukiZqVQLSJPMOv0oxQSutvvK3hoibwGakDOza+xRITB7cs2cECAwEAAQ==\n-----END PUBLIC KEY-----"
}
}
}]]
)
assert(code < 300, body)

-- Set up a route with jwt-auth
code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"jwt-auth": {}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
assert(code < 300, body)

-- This JWT has alg=HS256 in the header but targets the RS256 consumer
-- (key claim = "user-key-rs256"). It is HMAC-signed with the consumer's
-- public key, which would pass verification without the algorithm check.
local forged_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
.. ".eyJrZXkiOiJ1c2VyLWtleS1yczI1NiIsIm5iZiI6MTcyNzI3NDk4M30"
.. ".6H3x-DNrthHMtsQ72qZNrddTdDjEZuJQX6MNiEBFTOs"

local code, body = t('/hello?jwt=' .. forged_token, ngx.HTTP_GET)
ngx.status = code
ngx.print(body)
}
}
--- error_code: 401
--- response_body
{"message":"failed to verify jwt"}
--- error_log
failed to verify jwt: algorithm mismatch, expected RS256
Loading