fivem icon indicating copy to clipboard operation
fivem copied to clipboard

GET_PASSWORD_HASH / VERIFY_PASSWORD_HASH slow down the server thread

Open Korioz opened this issue 1 year ago • 2 comments

What happened?

Password hash natives uses bcrypt under the hood, bcrypt is designed to be slow the issue is not that it is slow, the issue is that calling password hashing natives will make the server thread hitch during the operations.

Maybe providing async alternatives natives and executing bcrypt operations in another thread would be a viable solution.

Expected result

No server thread hitch.

Reproduction steps

  1. Execute a server-side script containing this :
RegisterCommand('testpass', function()
    local pass = 'MyVeryStrongPassword123'
    
    local timeNow = GetGameTimer()
    local passHash = GetPasswordHash(pass)
    VerifyPasswordHash(pass, passHash)
    print(('%u ms elapsed during password operations'):format(GetGameTimer() - timeNow))
end, false)
  1. Type testpass in Console and see the output.

Importancy

Slight inconvenience

Area(s)

FXServer, Natives

Specific version(s)

Tested on Server 8867 and olders (this issue has been here for years)

Additional information

No response

Korioz avatar Jul 21 '24 14:07 Korioz

just use

local function getPasswordHash(pass)
    return joaat(pass)
end

local function verifyPasswordHash(pass, hash)
    return getPasswordHash(pass) == hash
end

FILIP-P-K avatar Aug 03 '24 06:08 FILIP-P-K

@Korioz This is a hack workaround till its fixed if you need it. https://github.com/CrunchyBadger/fivem-bcrypt-async

(Will probably break with different fx server versions, ik it doesn't work on 8981)

Working on latest.

Works same as natives but you need to use exports.

CrunchyBadger avatar Aug 08 '24 05:08 CrunchyBadger

Test:

Citizen.CreateThread(function()
    local password = '123123'
    local hash = GetPasswordHash(password)

    print('--- Starting VerifyPasswordHash test ---')

    local iterations = 10

    local startTime = os.clock()

    for i = 1, iterations do
        local ok = VerifyPasswordHash(password, hash)
        print(('[%d/%d] Check returned %s'):format(i, iterations, tostring(ok)))
    end

    local endTime = os.clock()
    local durationMs = (endTime - startTime) * 1000

    print(('--- Completed %d checks in %.2f ms (%.2f ms per check) ---'):format(iterations, durationMs, durationMs / iterations))
end)

Result:

[      script:test] --- Completed 10 checks in 1661.00 ms (166.10 ms per check) ---
[ citizen-server-impl] server thread hitch warning: timer interval of 1887 milliseconds

These native methods (GetPasswordHash / VerifyPasswordHash) clearly need improvement. Either they should be optimized for speed, or executed in a separate thread to avoid blocking the main server loop. Currently, each password verification can take over 100ms, which is unacceptable for high player concurrency.

aioeieoiao avatar Jul 19 '25 19:07 aioeieoiao

@FabianTerhorst Have you made any progress on solving the issue?

aioeieoiao avatar Jul 19 '25 19:07 aioeieoiao

I can implement the async methods if that's what's required

DaniGP17 avatar Jul 19 '25 19:07 DaniGP17

Yes async execution in another thread or such.

Korioz avatar Jul 20 '25 14:07 Korioz

@FabianTerhorst Have you made any progress on solving the issue?

Have you tried using node22 together with https://github.com/citizenfx/node-rebuild ?

Make sure to specify the correct node version that is used in the command line options.

FabianTerhorst avatar Jul 20 '25 17:07 FabianTerhorst

@FabianTerhorst Have you made any progress on solving the issue?

Have you tried using node22 together with https://github.com/citizenfx/node-rebuild ?

Make sure to specify the correct node version that is used in the command line options.

I used Lua

aioeieoiao avatar Jul 22 '25 05:07 aioeieoiao