Skip to content

feat: As a user, I want admin key auto-generation to use a cryptographically secure random source, so that auto-generated keys are not predictable or brute-forceable #13092

@janiussyafiq

Description

@janiussyafiq

Description

The current implementation of admin key auto-generation in apisix/core/id.lua uses math.random() to generate the key:

apisix/apisix/core/id.lua

Lines 108 to 112 in 4990927

admin_keys[i].key = ""
for _ = 1, 32 do
admin_keys[i].key = admin_keys[i].key ..
string.char(math.random(65, 90) + math.random(0, 1) * 32)
end

This has two security concerns:

  1. math.random is a predictable PRNG
    math.random is not a cryptographically secure pseudo-random number generator (CSPRNG). It is seeded predictably, meaning an attacker with knowledge of the seed or timing information could reconstruct or predict the generated key.

  2. Limited character set reduces entropy
    The generated key only uses A–Z and a–z (52 characters), giving approximately 5.7 bits of entropy per character.
    Over 32 characters this yields ~182 bits of theoretical entropy, but the effective entropy is significantly lower due to the use of a predictable PRNG.

Suggested improvement:

Both lua-resty-random and lua-resty-string are already available in the APISIX codebase (used in apisix/patch.lua and various plugins). A more secure implementation could leverage these existing dependencies:

local resty_random = require("resty.random")
local resty_str    = require("resty.string")
local key = resty_str.to_hex(resty_random.bytes(16)) -- 32 hex chars, 128 bits of true entropy                                           

resty.random.bytes() is backed by OpenSSL's RAND_bytes, making it a proper CSPRNG. Combined with hex encoding via resty.string.to_hex(), this produces a 32-character alphanumeric key with 128 bits of true entropy — a significant improvement over the current approach with no new dependencies required.

This issue was identified during the fix for #12170 . Since it is a separate concern, it is being tracked here independently.

Credits: inspired by @fekitibi from #12170 (comment)

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    Status

    📋 Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions