3 ๋ถ„ ์†Œ์š”

Bcrypt & Jsonwebtoken ๐Ÿ™€

โ€œ๋ณด์•ˆ ์‹œ์Šคํ…œ์€ ๊ฐ€์žฅ ์•ฝํ•œ ์—ฐ๊ฒฐ ๊ณ ๋ฆฌ๋งŒํผ๋งŒ ๊ฐ•ํ•˜๋‹ค.โ€

ํŠน์ •๋ถ€๋ถ„์˜ ๋ณด์•ˆ์ด ์•„๋ฌด๋ฆฌ ๊ฐ•ํ•˜๋‹ค๊ณ  ํ•˜๋”๋ผ๋„ ๋‹ค๋ฅธ๋ถ€๋ถ„์—์„œ ๋ณด์•ˆ์ด ๋šซ๋ ค๋ฒ„๋ฆฌ๋ฉด ์˜๋ฏธ๊ฐ€ ์—†๋‹ค.

๋”ฐ๋ผ์„œ ๋ณด์•ˆ ์‹œ์Šคํ…œ์˜ ์•ˆ์ •์„ฑ์€ โ€˜๊ฐ•ํ•œ ๋ถ€๋ถ„์ด ์–ผ๋งˆ๋‚˜ ๊ฐ•ํ•œ๊ฐ€โ€™๋ณด๋‹ค๋Š” โ€˜์•ฝํ•œ ๋ถ€๋ถ„์ด ์–ผ๋งˆ๋‚˜ ์•ฝํ•œ๊ฐ€โ€™์— ๋”ฐ๋ผ์„œ ์ขŒ์šฐ๋œ๋‹ค.



๋‹จ๋ฐฉํ–ฅ ํ•ด์‹œ ํ•จ์ˆ˜

๋‹จ๋ฐฉํ–ฅ ํ•ด์‹œ ํ•จ์ˆ˜ : ์ˆ˜ํ•™์ ์ธ ์—ฐ์‚ฐ์„ ํ†ตํ•ด ์›๋ณธ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณ€ํ™˜ํ•˜์—ฌ ์•”ํ˜ธํ™”๋œ ๋ฉ”์‹œ์ง€์ธ ๋‹ค์ด์ œ์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.. ์›๋ณธ ๋ฉ”์‹œ์ง€๋ฅผ ์•Œ๋ฉด ์•”ํ˜ธํ™”๋œ ๋ฉ”์‹œ์ง€๋ฅผ ๊ตฌํ•˜๊ธฐ๋Š” ์‰ฝ์ง€๋งŒ ์•”ํ˜ธํ™”๋œ ๋ฉ”์‹œ์ง€๋กœ๋Š” ์›๋ณธ ๋ฉ”์‹œ์ง€๋ฅผ ๊ตฌํ•  ์ˆ˜ ์—†์–ด์•ผ ํ•˜๋ฉฐ ์ด๋ฅผ '๋‹จ๋ฐฉํ–ฅ์„ฑ'์ด๋ผ๊ณ  ํ•œ๋‹ค.

์˜ˆ๋ฅผ ๋“ค๋ฉด โ€œabcdโ€๋ผ๋Š” ๋ฌธ์ž์—ด์€ ํ•ด์‹œ์•Œ๊ณ ๋ฆฌ์ฆ˜์— ์˜ํ•ด โ€œadasfuaokfa32423823joegnsvd324refwdoiepoht23n34โ€ ๊ฐ™์€ ๋ฌธ์ž์—ด๋กœ ์ธ์ฝ”๋”ฉ๋  ์ˆ˜ ์žˆ๋‹ค.

์œ„์˜ ๊ฐ’์„ ์ €์žฅํ•˜๋ฉด ์‚ฌ์šฉ์ž์˜ ํŒจ์Šค์›Œ๋“œ๋ฅผ ์ง์ ‘ ์ €์žฅํ•˜๋Š” ์œ„ํ—˜์„ ํ”ผํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธํ•  ๋•Œ ํŒจ์Šค์›Œ๋“œ๋ฅผ ์ž…๋ ฅํ•˜๋ฉด, ์ด๋ฅผ ํ•ด์‹œํ•œ ๊ฐ’์„ ์ €์žฅ๋œ ๊ฐ’๊ณผ ๋น„๊ตํ•˜์—ฌ ์ผ์น˜ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด ํŠน์ง•์„ avalanche ํšจ๊ณผ๋ผ๊ณ  ํ•˜๋ฉฐ, ์‚ฌ์šฉ์ž์˜ ์›๋ณธ ํŒจ์Šค์›Œ๋“œ๋ฅผ ์ถ”๋ก ํ•˜๊ธฐ ์–ด๋ ต๊ฒŒ ๋งŒ๋“œ๋Š” ์ค‘์š”ํ•œ ์š”์†Œ์ด๋‹ค.




๋‹จ๋ฐฉํ–ฅ ํ•ด์‹œ ํ•จ์ˆ˜์˜ ๋ฌธ์ œ์ 

๋™์ผํ•œ ๋ฉ”์‹œ์ง€๊ฐ€ ์–ธ์ œ๋‚˜ ๋™์ผํ•œ ๋‹ค์ด์ œ์ŠคํŠธ๋ฅผ ๊ฐ–๋Š”๋‹ค๋ฉด, ๊ณต๊ฒฉ์ž๊ฐ€ ์ „์ฒ˜๋ฆฌ(pre-computing)๋œ ๋‹ค์ด์ œ์ŠคํŠธ๋ฅผ ๊ฐ€๋Šฅํ•œ ํ•œ ๋งŽ์ด ํ™•๋ณดํ•œ ๋‹ค์Œ ์ด๋ฅผ ํƒˆ์ทจํ•œ ๋‹ค์ด์ œ์ŠคํŠธ์™€ ๋น„๊ตํ•ด ์›๋ณธ ๋ฉ”์‹œ์ง€๋ฅผ ์ฐพ์•„๋‚ด๊ฑฐ๋‚˜ ๋™์ผํ•œ ํšจ๊ณผ์˜ ๋ฉ”์‹œ์ง€๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค.

์ด์™€ ๊ฐ™์€ ๋‹ค์ด์ œ์ŠคํŠธ ๋ชฉ๋ก์„ ๋ ˆ์ธ๋ณด์šฐ ํ…Œ์ด๋ธ”(rainbow table)์ด๋ผ ํ•˜๊ณ , ์ด์™€ ๊ฐ™์€ ๊ณต๊ฒฉ ๋ฐฉ์‹์„ ๋ ˆ์ธ๋ณด์šฐ ๊ณต๊ฒฉ(rainbow attack)์ด๋ผ ํ•œ๋‹ค. ๊ฒŒ๋‹ค๊ฐ€ ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž์˜ ํŒจ์Šค์›Œ๋“œ๊ฐ€ ๊ฐ™์œผ๋ฉด ๋‹ค์ด์ œ์ŠคํŠธ๋„ ๊ฐ™์œผ๋ฏ€๋กœ ํ•œ๊บผ๋ฒˆ์— ๋ชจ๋‘ ์ •๋ณด๊ฐ€ ํƒˆ์ทจ๋  ์ˆ˜ ์žˆ๋‹ค.




๋‹จ๋ฐฉํ–ฅ ํ•ด์‹œ ํ•จ์ˆ˜ ๋ณด์™„ํ•˜๊ธฐ

์†”ํŒ…(salting) : ๋‹จ๋ฐฉํ–ฅ ํ•ด์‹œ ํ•จ์ˆ˜์—์„œ ๋‹ค์ด์ œ์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ์ถ”๊ฐ€๋˜๋Š” ๋ฐ”์ดํŠธ ๋‹จ์œ„์˜ ์ž„์˜์˜ ๋ฌธ์ž์—ด์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด ์›๋ณธ ๋ฉ”์‹œ์ง€์— ๋ฌธ์ž์—ด์„ ์ถ”๊ฐ€ํ•˜์—ฌ ๋‹ค์ด์ œ์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์„ ์†”ํŒ…(salting)์ด๋ผ ํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด "abcd"๋ผ๋Š” ๋ฌธ์ž์—ด์— ์†”ํŠธ์ธ "8zff4fgflgfd93fgdl4fgdgf4mlf45p1"๋ฅผ ์ถ”๊ฐ€ํ•ด ๋‹ค์ด์ œ์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋ฉด, ๊ณต๊ฒฉ์ž๊ฐ€ โ€œredfl0werโ€์˜ ๋‹ค์ด์ œ์ŠคํŠธ๋ฅผ ์•Œ์•„๋‚ด๋”๋ผ๋„ ์†”ํŒ…๋œ ๋‹ค์ด์ œ์ŠคํŠธ๋ฅผ ๋Œ€์ƒ์œผ๋กœ ํŒจ์Šค์›Œ๋“œ ์ผ์น˜ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๊ธฐ ์–ด๋ ต๋‹ค. ๋˜ํ•œ ์‚ฌ์šฉ์ž๋ณ„๋กœ ๋‹ค๋ฅธ ์†”ํŠธ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ๋™์ผํ•œ ํŒจ์Šค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ์šฉ์ž์˜ ๋‹ค์ด์ œ์ŠคํŠธ๊ฐ€ ๋‹ค๋ฅด๊ฒŒ ์ƒ์„ฑ๋˜์–ด ์ธ์‹ ๊ฐ€๋Šฅ์„ฑ ๋ฌธ์ œ๊ฐ€ ํฌ๊ฒŒ ๊ฐœ์„ ๋œ๋‹ค.

์†”ํŠธ์™€ ํŒจ์Šค์›Œ๋“œ์˜ ๋‹ค์ด์ œ์ŠคํŠธ๋ฅผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅํ•˜๊ณ , ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธํ•  ๋•Œ ์ž…๋ ฅํ•œ ํŒจ์Šค์›Œ๋“œ๋ฅผ ํ•ด์‹œํ•˜์—ฌ ์ผ์น˜ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•  ๋•Œ์—๋Š” ๋ชจ๋“  ํŒจ์Šค์›Œ๋“œ๊ฐ€ ๊ณ ์œ ์˜ ์†”ํŠธ๋ฅผ ๊ฐ–๊ณ  ์†”ํŠธ์˜ ๊ธธ์ด๋Š” 32๋ฐ”์ดํŠธ ์ด์ƒ์ด์–ด์•ผ ์†”ํŠธ์™€ ๋‹ค์ด์ œ์ŠคํŠธ๋ฅผ ์ถ”์ธกํ•˜๊ธฐ ์–ด๋ ต๋‹ค.


ํ‚ค ์ŠคํŠธ๋ ˆ์นญ(key stretching) : ์ž…๋ ฅํ•œ ํŒจ์Šค์›Œ๋“œ์˜ ๋‹ค์ด์ œ์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์ƒ์„ฑ๋œ ๋‹ค์ด์ œ์ŠคํŠธ๋ฅผ ์ž…๋ ฅ ๊ฐ’์œผ๋กœ ํ•˜์—ฌ ๋‹ค์ด์ œ์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ๋˜ ์ด๋ฅผ ๋ฐ˜๋ณตํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ๋‹ค์ด์ œ์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ž…๋ ฅํ•œ ํŒจ์Šค์›Œ๋“œ๋ฅผ ๋™์ผํ•œ ํšŸ์ˆ˜๋งŒํผ ํ•ด์‹œํ•ด์•ผ๋งŒ ์ž…๋ ฅํ•œ ํŒจ์Šค์›Œ๋“œ์˜ ์ผ์น˜ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๊ฒƒ์ด ๊ธฐ๋ณธ์ ์ธ ํ‚ค ์ŠคํŠธ๋ ˆ์นญ ๊ณผ์ •์ด๋‹ค.




bcrypt

bcrypt : ์• ์ดˆ๋ถ€ํ„ฐ ํŒจ์Šค์›Œ๋“œ ์ €์žฅ์„ ๋ชฉ์ ์œผ๋กœ ์„ค๊ณ„๋˜์—ˆ๋‹ค. Niels Provos์™€ David Maziรจres๊ฐ€ 1999๋…„ ๋ฐœํ‘œํ–ˆ๊ณ  ํ˜„์žฌ๊นŒ์ง€ ์‚ฌ์šฉ๋˜๋Š” ๊ฐ€์žฅ ๊ฐ•๋ ฅํ•œ ํ•ด์‹œ ๋ฉ”์ปค๋‹ˆ์ฆ˜ ์ค‘ ํ•˜๋‚˜์ด๋‹ค. bcrypt๋Š” ์ž…๋ ฅ ๊ฐ’์œผ๋กœ 72 bytes character๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ์ œ์•ฝ์ด ์žˆ๋‹ค.
# terminal
$ npm install bcrypt
import bcrypt from 'bcrypt';

const salt = bcrypt.genSaltSync(10);
const hash = bcrypt.hashSync(password, salt);

๊ฐ™์€ ํŒจ์Šค์›Œ๋“œ๋ผํ•ด๋„ ์†”ํŠธ๋ถ€๋ถ„์ด ๋งค๋ฒˆ ๋ฐ”๋€Œ๋Š”๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

bcrypt์˜ hashing์˜ ๊ฒฝ์šฐ์— CPU์˜ ์˜ํ–ฅ์„ ๋งŽ์ด ๋ฐ›๋Š”๋ฐ, sync๋กœ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด ์ด๋ฒคํŠธ ๋ฃจํ”„์—์„œ block ๋‹นํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ทธ๋ž˜์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ด์šฉํ•ด์„œ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ๊ดœ์ฐฎ์ง€๋งŒ, ์„œ๋ฒ„์—์„œ ์‚ฌ์šฉํ•  ๋• async ๋ชจ๋“œ๋ฅผ ๊ถŒ์žฅํ•˜๊ณ  ์žˆ๋‹ค.

const signIn = async (password) => {

const comparePw = await bcrypt.compare(password, users.password)

if(!coparePw) throw new Error('id , pw๊ฐ€ ๋งž์ง€ ์•Š์Šต๋‹ˆ๋‹ค.');

}




JWT

JWT(Json Web Token) : ๊ฐ ๊ฐ์ฒด ์‚ฌ์ด์—์„œ ์†์„ฑ ์ •๋ณด์„ JSON ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋กœ ํ‘œํ˜„ํ•˜๊ณ  ์•”ํ˜ธํ™”๋ฅผ ํ†ตํ•ด ์ •๋ณด๋ฅผ ์ „๋‹ฌํ•˜๋Š” Token์˜ ๋Œ€ํ‘œ

JWT๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฐ€์žฅ ํ”ํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค.

์œ ์ €๊ฐ€ ๋กœ๊ทธ์ธ์„ ํ•˜๋ฉด, ์„œ๋ฒ„๋Š” ์œ ์ €์˜ ์ •๋ณด์— ๊ธฐ๋ฐ˜ํ•œ ํ† ํฐ์„ ๋ฐœ๊ธ‰ํ•˜์—ฌ ์œ ์ €์—๊ฒŒ ์ „๋‹ฌ.

๊ทธ ํ›„, ์œ ์ €๊ฐ€ ์„œ๋ฒ„์— ์š”์ฒญ์„ ํ•  ๋•Œ๋งˆ๋‹ค JWT๋ฅผ ํฌํ•จํ•˜์—ฌ ์ „๋‹ฌ.

์„œ๋ฒ„๊ฐ€ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ์„œ ์š”์ฒญ์„ ๋ฐ›์„ ๋•Œ๋งˆ๋‹ค, ํ•ด๋‹น ํ† ํฐ์ด ์œ ํšจํ•˜๊ณ  ์ธ์ฆ๋๋Š”์ง€ ๊ฒ€์ฆ์„ ํ•˜๊ณ , ์œ ์ €๊ฐ€ ์š”์ฒญํ•œ ์ž‘์—…์— ๊ถŒํ•œ์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜์—ฌ ์ž‘์—…์„ ์ฒ˜๋ฆฌ.

์ฆ‰, ์„œ๋ฒ„ ์ธก์—์„œ๋Š” ์œ ์ €์˜ ์„ธ์…˜์„ ์œ ์ง€ํ•  ํ•„์š”๊ฐ€ ์—†์Œ.

์œ ์ €๊ฐ€ ๋กœ๊ทธ์ธ๋˜์–ด์žˆ๋Š”์ง€ ์•ˆ๋˜์–ด์žˆ๋Š”์ง€ ์‹ ๊ฒฝ ์“ธ ํ•„์š”๊ฐ€ ์—†๊ณ , ์œ ์ €๊ฐ€ ์š”์ฒญ์„ ํ–ˆ์„ ๋•Œ ํ† ํฐ๋งŒ ํ™•์ธํ•˜๋ฉด ๋˜๋‹ˆ, ์„ธ์…˜ ๊ด€๋ฆฌ๊ฐ€ ํ•„์š” ์—†์–ด์„œ ์„œ๋ฒ„ ์ž์›์„ ๋งŽ์ด ์•„๋‚„ ์ˆ˜ ์žˆ์Œ.




JMT ๊ตฌ์กฐ

Header : ํƒ€์ž…(JWT)๊ณผ ์•Œ๊ณ ๋ฆฌ์ฆ˜(BASE64 ๊ฐ™์€)์„ ๋‹ด๋Š”๋‹ค.

Payload : ๋ณดํ†ต ์œ ์ €์ •๋ณด(id๊ฐ™์€)์™€ ๋งŒ๋ฃŒ๊ธฐ๊ฐ„์ด ๊ฐ์ฒดํ˜•์œผ๋กœ ๋‹ด๊ธด๋‹ค.

Signature : header, payload๋ฅผ ์ธ์ฝ”๋”ฉ ํ•œ ๊ฐ’์„ ํ•ฉ์นœ๋’ค SECRET_KEY๋กœ ํ•ด์‰ฌํ•œ๋‹ค.( ํ™˜๊ฒฝ๋ณ€์ˆ˜๋กœ ์„ค์ • )




์‚ฌ์šฉ๋ฒ•

# npm install jsonwebtoken
JWT_SECRET=JwTsEcReTkEyOrHaShInG

.evn์—์„œ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋กœ ์‹œํฌ๋ฆฟํ‚ค ์„ค์ •

const jwt = require('jsonwebtoken');

  const token = jwt.sign(
    {
      id: users.id,
    },
    process.env.JWT_SECRET,
    {
      expiresIn: '60m', // ์œ ํšจ ์‹œ๊ฐ„์€ 60๋ถ„
    }
  );

sign()

1๋ฒˆ์งธ ์ธ์ž : payload ์ฆ‰, ๋ณด๋‚ผ๋‚ด์šฉ. (์ค‘์š”ํ•œ ์ •๋ณด๋Š” ๋‹ด์ง€์•Š๋„๋ก ํ• ๊ฒƒ)

2๋ฒˆ์งธ ์ธ์ž : ๋น„๋ฐ€ํ‚ค ( gitignore์— ์ˆจ๊ธธ๊ฒƒ์„ ๊ถŒ์žฅ )

3๋ฒˆ์งธ ์ธ์ž : ํ† ํฐ์ •๋ณด ( ์ฃผ๋กœ ์œ ํšจ๊ธฐ๊ฐ„ )

4๋ฒˆ์งธ ์ธ์ž : ์ฝœ๋ฐฑํ•จ์ˆ˜ ( ์‚ฌ์šฉํ•˜์ง€์•Š์œผ๋ฉด ๋™๊ธฐ์‹์œผ๋กœ ์ฒ˜๋ฆฌ๋œ๋‹ค. )

const verifyToken = (token) => {
  try {
    return jwt.verify(token, process.env.JWT_SECRET);
  } catch (err) {
    return null;
  }
};

const Authentication = (req, res, next) => {
  const token = req.cookies.user; // token๊ฐ€์ ธ์˜ค๊ธฐ

  const vaildToken = verifyToken(token);

  if (vaildToken) {
    req.userId = vaildToken.id;
    next();
  } else {
    res.status(400).send('ํ† ํฐ์ด ์œ ํšจํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.');
    return;
  }
};

์ฃผ๋กœ ์ธ์ฆ์— ์‚ฌ์šฉ๋œ๋‹ค.

์—…๋ฐ์ดํŠธ: