-
Notifications
You must be signed in to change notification settings - Fork 0
Password and JSON Webtokens
Bij het registreren van gebruikers is het van belang dat eventuele opgevraagde wachtwoorden worden gehashed.
Waarom?
Stel dat op de een of andere manier ons database wordt gehacked.. De hacker heeft op dat moment de mogelijkheid om wachtwoorden te bekijken van gebruikers.
Onze dating is dan niet zo belangrijk, maar er zijn best veel mensen die op het internet dezelfde wachtwoorden gebruiken. Hackers zouden deze mensen harder kunnen raken door op platformen in te loggen.
Het is eigenlijk niet goed dat mensen dezelfde wachtwoorden gebruiken. Maar het is dat onze taak als developers om een manier te zoeken om die mensen te beschermen.
Tijdens mijn onderzoek naar het hashen van wachtwoorden ben ik tegen gekomen wat het verschil is van Encryption en Hashing.
Encryption | Hashing |
---|---|
✳️ Encryption is het altijd mogelijk om de original value terug te krijgen | ✳️ Hashing algorithms zijn one-way algorithms en maken het niet mogelijk om original values terug te krijgen |
Allereerst heb ik een package geinstalleerd genaamd bcrypt. Dit is een library die helpt met het hashen van wachtwoorden. Het is ontworpen door Niels Provos en David Mazières.
De bcrypt function verwacht een promise .hash
verwacht twee argumenten.. Het wachtwoord, het tweede argument
geeft aan hoevaak het algoritme moet worden gerund. Ik heb voor 8 gekozen omdat het goed in balans is met security en snelheid 8 wordt ook aangeraden door de makers van het algoritme. Een te hoge waarde is zal veel tijd nemen om de algoritme uit te voeren. Een te lage waarde zal een zwak wachtwoord genereren.
Omdat hashing one-way is moeten we deze functie gebruiken om de ingevoerde wachtwoord te vergelijken Met wachtwoord in onze database
const bcrypt = require('bcrypt');
const myFunc = async () => {
const password = 'pixbyIsLit';
const hashedPassword = await bcrypt.hash(password, 8);
console.log(password);
console.log(hashedPassword);
const isMatch = await bcrypt.compare(password, hashedPassword);
console.log(isMatch); // Returns a boolean
};
myFunc();
Hetgeen wat ik meegeef aan de model. Dat is dus de user met de data van req.body zie server.js voor de kleine api route waar ik users aanmaak
user.isModified('password')
Alleen wanneer het wachtwoord wordt gewijzigt willen we de hash functie toepassen.
Dus niet elke keer als de user inlogt!
userSchema.pre('save', async function (next) {
const user = this
if (user.isModified('password')) {
user.password = await bcrypt.hash(user.password, 8) // Zie playground brcypt.js
}
// Net als met middlewares in express, wordt next geroepen als
// de middleware is afgerond en model in dit geval kan worden opgeslagen
// Als next niet wordt geroepen, blijft de middleware hangen
next()
})
In deze userSchema zoek ik dus in het database of het wachtwoord dat de gebruiker meegeeft, overeenkomt met het gehashte wachtwoord van de desbetreffende gebruiker.
userSchema.statics.findByCredentials = async (name, password) => {
const user = await User.findOne({ name })
if (!user) {
throw new Error('This user does not exist..')
}
const isMatch = await bcrypt.compare(password, user.password)
if (!isMatch) {
throw new Error('Incorrect password..')
}
return user
}
JWT gebruik ik om een authentication systeem te bouwen. JSON web tokens kunnen voor meerdere dingen worden gebruikt maar worden het meest gebruikt voor Authentication.
De package 'jsonwebtoken' wekrt als volgt.
Om een token te makent dient te functie .sign()
te worden afgeroepen. De functie vraagt als eerste argument een unique identifier waarmee de gebruiker gevonden kan worden en als tweede argument een wachtwoord.
Met jwt.verify()
kunnen we tokens verifieren. Deze functie vraagt de een jwt token en hetzelfde wachtwoord waarmee de tokens worden gesigned.
Als de functie is gelukt dan returned deze functie een gebruiker terug en zo niet dan krijg je een error in de console die aangeeft dat er een Invalid Signature is.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiJicmlhbmJhd3VhaCIsImlhdCI6MTU5MDc3MDU5Mn0.4wLvmgPKrfX4AFr4B-WOzCKplW9Oo1eoEpIfE746mhA
const jwt = require('jsonwebtoken');
const myFunction = async () => {
const token = jwt.sign({ _id: 'brianbawuah' } /* Unique identiefier! van object. (_id dus) */, 'projectTechIsLeuk', { expiresIn: '2 days' });
console.log(token);
const data = jwt.verify(token, 'projectTechIsLeuk');
console.log(data);
};
myFunction();
JSON Webtokens bestaan uit drie delen.
- Header
- Payload
- Signature
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
Base64 string bestaat uit meta data
eyJfaWQiOiJicmlhbmJhd3VhaCIsImlhdCI6MTU5MDc3MDU5Mn0. === {"_id":"brianbawuah","iat":1590770592}
De payload/ body van jsonwebtoken. Zoals te zien is dit de data
4wLvmgPKrfX4AFr4B-WOzCKplW9Oo1eoEpIfE746mhA
Dit is de signature waarmee de token mee geverifieerd kan worden.
"The point of jsonwebtokens is not to hide the data.." The whole point is om een token te creeeren dat we kunnen verifieren met onze jwt secret
Hier laat ik zien hoe we JWT gebruiken in onze applicatie. Dit is een userSchema die we gebruiken op het moment van registreren en inloggen. Met deze schema maken we dus een jwt token aan voor een user. We geven een unique identifier mee zoals de functie verwacht. In dit geval de _id van de gebruiker.
Daarna return ik met de concat functie een nieuwe array terug met de oude tokens en die nieuw gegenereerde token en die sla ik op in de user.tokens
array.
// Here I generate a new token for the user
userSchema.methods.generateAuthToken = async function () {
// Makes it easier to refer to
const user = this
const token = jwt.sign(
{
_id: user._id.toString(),
} /* id is ObjectId(5ed0ef97405ebd524ada62d8).. jwt verwacht een string */,
process.env.JWT_SECRET,
)
// Concat returned a new array with all the values
user.tokens = user.tokens.concat({ token }) // See user mode
await user.save() // Save token in mongo
return token
}
- JWT.IO. (z.d.). Geraadpleegd op 23 juni 2020, van https://jwt.io/
- Wikipedia contributors. (2020, 13 juni). Bcrypt. Geraadpleegd van https://en.wikipedia.org/wiki/Bcrypt
- The Real Difference Between Hashing and Encryption. (z.d.). Geraadpleegd op 23 juni 2020, van https://www.solarwindsmsp.com/blog/hashing-vs-encryption%C2%A0