Password-Hashing-As-A-Service
PHAAS? What acronyms you get when everything is as a service
Can’t I hash my own passwords?
Companies have a vested interest in ensuring passwords in their care are handled securely. A centralized PHAAS could help by ensuring that passwords are encoded and verified according to company standards and best practices. Centralizing password hashing also removes security-sensitive code from individual applications and standardizes it in a single location. This also reveals which applications perform password hashing and which algorithms are used.
Why not Hashing-As-A-Service?
I’m not sure that hashing as a generic capability makes a lot of sense as a centralized function. Nearly every modern language has either built-in or widely-available library support for common cryptographic hashing algorithms, such as MD#, SHA#. Hashing algorithms are typically used to compare downloaded files to ensure integrity or to compare two files. The idea of passing files or large amounts of data to a centralized service to run a SHA256 seems unwarranted, except for the case of handling passwords.
The details… the details
Companies may have several different allowed password hashing schemes, to allow flexibility as legacy systems are brought into compliance, or to allow different levels of protection. The <scheme>
path parameter in the HTTP examples below indicates that a set of rules (identified by the value of <scheme>
) will be applied to the provided password.
What kinds of rules might apply to hashing passwords? Primarily the choice of hashing algorithm such as bcrypt, MD#, SHA#, or other modern hashing algorithms. Note that MD# and SHA# should never be used for hashing passwords.
If we choose bcrypt, there are still several choices to make that could be decided by company standard. The bcrypt cost is often tuned so that it takes one second to hash a password — or possibly to a higher cost as per guidelines. Let’s be honest — is anyone actually doing this tuning? The bcrypt algorithm also needs a crytographically secure pseudo-random source to generate the salt. Companies could also specify running the password through a sequence of steps (such as pre-hashing or pre-encoding) before the crytographic hash.
Note that a centralized PHAAS would NOT store the password. It’s up to the consumer to store the password and provide it back to the centralized service for verification. Note also that exposing expensive hashing as a function would need to be an authorized-only capability, to prevent denial of service or participation in a brute-force attack — whether intentional or not.
Here’s an example of a request to hash a password given scheme=bcryptplain
, which in this case might indicate that the password should be hashed using bcrypt algorithm version 2a with a cost of 10 and no pre-hashing or pre-encoding. It could be possible to POST with either a request body or URL parameters, but I prefer symmetric JSON-in-JSON-out requests, and I feel that POST bodies are more appropriate for a headless service (traffic to-and-from a crypto-as-a-service would likely never be seen from a browser).
POST /password/hash/bcryptplain HTTP/2
Authorization: Bearer eyJhbGc...
Content-Type: application/json
Content-Length: #{
"clearPassword": "myPassword123"
}< HTTP/2 200
< content-type: application/json
< content-length: #{
"opaquePassword": "$2a$10$FwcytWTfZQ3SzcBe.ojeD.BK1GwTi34V50wvggWUfizp.AFleYE0S"
}
Now we need a similar password verification capability, so that subsequent login attempts can be verified. I anticipate that such a function would rely on JSON responses, not HTTP status codes, to indicate verification pass or fail.
POST /password/verify/bcryptplain HTTP/2
Authorization: Bearer eyJhbGc...
Content-Type: application/json
Content-Length: #{
"clearPassword": "myPassword123",
"opaquePassword": "$2a$10$FwcytWTfZQ3SzcBe.ojeD.BK1GwTi34V50wvggWUfizp.AFleYE0S"
}< HTTP/2 200
< content-type: application/json
< content-length: #{
"matches": true
}
Who’s allowed to hash or verify passwords?
Both hashing and verification should require authorization (or be guarded through some other mechanism) because hashing and verification are expensive tasks and a centralized PHAAS would be easily attacked DOS.
I recommend that clients of PHAAS should be given access to a specific <scheme>
in order to accomplish their own objectives. This could be accomplished through an OAuth scope such as phaas.bcryptplain
to indicate the <scheme>
shown above. This grants access to both the hash
and verify
capability.
Could an implementation be open-sourced?
Of course! Note that there’s a lot of leeway in the choice of algorithms and rulesets (such as whether to pre-hash), meaning that the open-source component would either have those rules baked in or be easily extensible. It seems quite possible that this could be open-sourced in library form with some simple rulesets and then users could register their own rulesets. In a Java+Spring library this could possibly be done by registering @Beans
of type PasswordEncoder
with names corresponding to the <scheme>
.
Can this approach help migrate a legacy app to a better hashing scheme?
I think so! Let’s say legacy app corporateTreasure
is using SHA-256 and wants to migrate to using bcrypt. One approach is to invalidate all currently-hashed SHA-256 passwords and require the user to provide a new passwords that can be hashed with bcrypt. Another approach that spreads risk over time is to “strangle” the userbase from SHA-256 to bcrypt as passwords naturally expire, say every 90 days.
PHAAS could help with this by setting up a custom <scheme>
for application corporateTreasure
that only hashes uses bcrypt, but verifies using either bcrypt or SHA-256. Thus users that haven’t yet reset their password can still log in. After the password lifespan window (say 90 days) users that haven’t yet reset their password will have their user accounts locked until they can reset their password (which will use bcrypt).