A safer way to deal with passwords

  • Someone with access to the servers can easily look/log at the incoming plain-text passwords.
  • The server log can accidentally be logging plain-text password.
  • Just imagine…
  • Send cryptographic hashes instead of passwords.
  • Store strong cryptographic hashes on the server.

Send cryptographic hashes instead of passwords

<form action="javascript:" onsubmit="onSubmit(this)">
<input type="text" name="username" placeholder="username">
<input type="password" name="password" placeholder="password">
<input type="submit">
</form>
function onSubmit(form) {
(async()=> {
const formData = new FormData(form)
const password = formData.get("password")
const passwordHash = await securePasswordHash(password)
formData.append("passwordHash", passwordHash)
try {
const response = await fetch('/', {
method: 'POST',
body: formData
})
const text = await response.text()
if (response.status !== 200) {
if (text && text.length > 0) {
console.error(text)
} else {
console.error('There was an error')
}
return
}
document.body.innerHTML = text
} catch (e) {
console.error(e.message)
}
})()
}
async function securePasswordHash(password) {
if (!password) return null
let textEncoder = new TextEncoder()
let saltBuffer = textEncoder.encode(reverseString(password))
let encodedPassword = textEncoder.encode(password)
let baseKey = await window.crypto.subtle.importKey(
"raw",
encodedPassword,
"PBKDF2",
false,
["deriveBits"]
)
let keyBuffer = await window.crypto.subtle.deriveBits(
{
"name": "PBKDF2",
"hash": "SHA-256",
salt: saltBuffer,
"iterations": 5000
},
baseKey,
256
)
return arrayBufferToBase64(keyBuffer)
}

Store strong cryptographic hashes on the server.

let saltBuffer = crypto.randomBytes(32)
let derivedKey = crypto.pbkdf2Sync(data.passwordHash, saltBuffer, 100000, 32, 'sha256')
data.serverPasswordHash = saltBuffer.toString('base64') + ':' + derivedKey.toString('base64')
saltBuffer = new Buffer(reverseString(data.password))
derivedKey = crypto.pbkdf2Sync(data.password, saltBuffer, 5000, 32, 'sha256')
data.matchClientPasswordHash = derivedKey.toString('base64')
data.matched = data.matchClientPasswordHash === data.passwordHash
{
"username": "sal",
"password": "MyW3@kP@$$!",
"passwordHash": "IH+kRSeTPHvudfLZMCldXFmXnARQMgaCWGWu3gEX4mw=",
"serverPasswordHash": "a3k1RzHeGrkqRQRhy2qohCu6Cfcb+5UhcsZ3Bjtg8K4=:kuh0eM7sm+ujX5pQoAhCIyEUtmxPZb+/yBF/uINK8DA=",
"matchClientPasswordHash": "IH+kRSeTPHvudfLZMCldXFmXnARQMgaCWGWu3gEX4mw=",
"matched": true
}

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Salvador Guerrero

Salvador Guerrero

Computer Science Engineer, Cross-Platform App Developer, Open Source contributor. 🇲🇽🇺🇸