diff options
| author | Bryce Kwon <bryce@brycekwon.com> | |
|---|---|---|
| committer | Bryce Kwon <bryce@brycekwon.com> | |
| commit | ||
| parent | ||
| tree | ||
| download | ||
Spend a missing account's login on a real hash
The fixed SHA-512 stand-in matched only the documented setup, so a site
hashing with yescrypt, other rounds or bcrypt answered for missing and
real names in different times, and on OpenBSD it failed at once.
Diffstat (limited to 'custom/extensions/auth-file.lua')
| -rw-r--r-- | custom/extensions/auth-file.lua | 29 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1 file changed, 17 insertions, 12 deletions
diff --git a/custom/extensions/auth-file.lua b/custom/extensions/auth-file.lua index f43eb82..59e05cc 100644 --- a/custom/extensions/auth-file.lua +++ b/custom/extensions/auth-file.lua @@ -90,11 +90,6 @@ local cookie_insecure = false -- the password's length, and one longer than this is turned down unchecked. local max_password_bytes = 256 --- A throwaway hash of the documented shape, used only to spend the same work --- on a missing account as on a present one, so a failed login does not reveal --- by timing whether the user name exists. -local dummy_hash = "$6$rounds=300000$0000000000000000$" - -- One request reaches this script as an open, a write and a close, so what the -- open decodes is kept here for the calls that follow. local action, http, cgit, post @@ -129,6 +124,10 @@ end -- The hash is trimmed as well as the name because reading by line strips -- the newline but not a carriage return, so a CRLF users file would hand -- crypt a hash with a trailing \r and fail every login. +-- +-- A name with no account comes back as nil and another account's hash, so +-- a failed login can spend the same work on a hash of the same kind and +-- cost, and its timing does not tell whether the name exists. function account_hash(user) if user == nil then return nil @@ -138,15 +137,19 @@ function account_hash(user) if users_file == nil then return nil end + local stand_in = nil for line in users_file:lines() do local name, hash = string.match(line, "(.-):(.+)") - if name ~= nil and trim(name):lower() == wanted then - users_file:close() - return trim(hash) + if name ~= nil then + if trim(name):lower() == wanted then + users_file:close() + return trim(hash) + end + stand_in = stand_in or trim(hash) end end users_file:close() - return nil + return nil, stand_in end -- The users allowed into a repository come back keyed by lowercased name, and @@ -454,10 +457,12 @@ function authenticate_post() local password = post["password"] local ok = false if username ~= nil and password ~= nil and #password <= max_password_bytes then - local hash = account_hash(username) + local hash, stand_in = account_hash(username) if hash == nil then - -- Spend the work anyway, see dummy_hash. - unistd.crypt(password, dummy_hash) + -- Spend the work anyway, see account_hash. + if stand_in ~= nil then + unistd.crypt(password, stand_in) + end elseif constant_equals(hash, unistd.crypt(password, hash)) then ok = true end |
