yeeen 2020. 1. 15. 01:02

 

์‚ฌ์‹ค ํ”„๋กœ์ ํŠธ๋ฅผ ๋‹ค ๋๋‚ธ ํ›„ ํ•œ๊บผ๋ฒˆ์— ๋ฉ‹์ฐŒ๊ฒŒ ์ •๋ฆฌํ•˜๊ณ  ์‹ถ์—ˆ์ง€๋งŒ,,

๊ทธ๋Ÿฌ๊ธฐ์—” ๋„ˆ๋ฌด ์–‘์ด ๋งŽ์„ ๊ฒƒ ๊ฐ™์•„์„œ

์ด๋•Œ๊นŒ์ง€ ์ง„ํ–‰ํ•œ ๋ถ€๋ถ„ ๋ถ€๋ถ„ ์ •๋ฆฌํ•ด์„œ ์˜ฌ๋ฆฌ๊ธฐ๋กœ ํ–ˆ๋‹ค.

 

 

๊ธฐ๋ณธ์•„ํ‚คํ…์ณ

client (react) ↔ server (node.js) ↔ mysql (db) ์บ์‹œ์ฒ˜๋ฆฌ Redis

 

Node.js ์—์„œ mysql ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ ‘๊ทผ ๋ฐฉ๋ฒ•

 

  1. connection ๊ฐ์ฒด ์ƒ์„ฑํ•˜์—ฌ ๊ทธ ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•ด DB์™€ ํ†ต์‹ 
  2. connection ์„ค์ •์€ config ํด๋” ๋‚ด์— ์ €์žฅ

 

 

3. connection ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•

 

  createConnection()

  •     ๋งค๋ฒˆ connection ์ƒ์„ฑ → ๋น„ํšจ์œจ์  (์ƒ์„ฑ๋  ๋•Œ ๋งŽ์€ ์‹œ๊ฐ„ ์†Œ์š”๋˜๊ธฐ ๋•Œ๋ฌธ)
  •     createConnection() ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด connection ๊ฐ์ฒด ํ•˜๋‚˜ ์ƒ์„ฑ
  •     ์ข…๋ฃŒ: connection.end();

 

  createPool()

  •    createPool() ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด connection pool ์ƒ์„ฑ
  •    connection ์„ pool ์—์„œ ๊ฐ€์ ธ์™€ ์‚ฌ์šฉ ⇒ createConnection() ๋ณด๋‹ค ํšจ์œจ์ 
  •    connection์˜ ๊ฐœ์ˆ˜ ์ œํ•œ 0 ⇒ ๋ฐ˜ํ™˜ํ•ด์ฃผ์ง€ ์•Š์„ ๊ฒฝ์šฐ connection limit ์— ๊ฑธ๋ฆด ์ˆ˜ ์žˆ๋‹ค.
  •    connection ๋ฐ˜ํ™˜ : connection.release();

 

4. connection ์‚ฌ์šฉ ํ›„ ๋ฐ˜๋“œ์‹œ end(), release() ์ด์šฉํ•ด connection ๋Š์–ด์•ผ ํ•œ๋‹ค.

   => end(), release() ๋น„๋™๊ธฐ๋กœ ์ˆ˜ํ–‰ ⇒ connection.query()์˜ callback ํ•จ์ˆ˜ ๋‚ด์— ์ž‘์„ฑ

 

5. connection ์‚ฌ์šฉ ๋ฐฉ๋ฒ•

  • query ๋ฌธ์€ string, values ๋Š” query ๋ฌธ์— ๋“ค์–ด๊ฐˆ ๋™์ ์œผ๋กœ ํ• ๋‹น๋  ๋ณ€์ˆ˜

    1. select ๊ฒฐ๊ณผ ๊ฐ’ : [{object1}, {object2}, {object3},...] → ํŠน์ • object ์ ‘๊ทผ ์‹œ result[i].value

    2. insert/ update / delete ์˜ ๊ฒฐ๊ณผ ๊ฐ’ : ๊ฒฐ๊ณผ ๊ฐ’์ด ๋‹ด๊ธด json ๊ฐ์ฒด

 

Node.js Password Encryption

 

์•”ํ˜ธํ™”๋ฅผ ์œ„ํ•ด crypto ๋ชจ๋“ˆ ์‚ฌ์šฉ

 

pbkdf2 - ๋‹จ๋ฐฉํ–ฅ์•”ํ˜ธํ™”

 

   hash : ํ•ด์‹œ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ( ex sha256, sha512 ...) → ๋ฌธ์ž์—ด์˜ ํŠน์ • ๊ทœ์น™์„ ์ด์šฉํ•ด ๋‹ค๋ฅธ ๋ฌธ์ž์—ด๋กœ ์น˜ํ™˜

   salt : ํ•ด์‹ฑ์„ ํ•  ๋•Œ ์ถ”๊ฐ€๋˜๋Š” ์ž„์˜์˜ ๋ฌธ์ž์—ด ( salt๋ฅผ ํ•ด์‹ฑํ•  ๋ฌธ์ž์—ด์— ์ถ”๊ฐ€ํ•˜์—ฌ ํ•ด์‹ฑํ•˜๋Š” ๊ฒƒ : salting)

    ⇒ ๋” ๊ฐ•๋ ฅํ•˜๊ฒŒ ์•”ํ˜ธํ™” ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

const salt = await crypto.randomBytes(32);

    key stretching : hashing ํ•จ์ˆ˜๋ฅผ ๋ฐ˜๋ณตํ•˜์—ฌ ํ•ด์‹ฑํ•˜๋Š” ๊ฒƒ.

    salt ๊ฐ’์„ ์•Œ๋”๋ผ๋„ ๋ฐ˜๋ณตํšŸ์ˆ˜๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์œผ๋ฉด digest ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†๋‹ค. ( digest : salt + password string ) 

    ๋‹จ์ˆœ ํ•ด์‹ฑ์€ 1์ดˆ์— ์ˆ˜๋งŒ ~ ์ˆ˜์‹ญ์–ต๊ฐœ์˜ Digest ์ƒ์„ฑ๊ฐ€๋Šฅ

    -> GPU๋ฅผ ์‚ฌ์šฉํ•œ brute-force ๊ณต๊ฒฉ์— ์‰ฝ๊ฒŒ ๋šซ๋ฆฐ๋‹ค! ⇒ salting + key stretching ํ•จ๊ป˜ ์‚ฌ์šฉ

 

    

// password encryption ๊ฒฐ๊ณผ
const pwHashed = await crypto.pbkdf2(user_pw, salt.toString('base64'), 10000, 32, 'sha512');

 

Node.js ํ† ํฐ

 

Token ๊ธฐ๋ฐ˜ ์ธ์ฆ

์ž‘๋™์›๋ฆฌ : Statelsess ์„œ๋ฒ„

ํด๋ผ์ด์–ธํŠธ ↔ ์„œ๋ฒ„ ๊ฐ„์˜ ์ƒํƒœ ์œ ์ง€ ํ•˜์ง€ ์•Š๋Š”๋‹ค.

( ์ฆ‰ , ์„œ๋ฒ„๋Š” ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ๋“ค์–ด์˜ค๋Š” ์š”์ฒญ๋งŒ์œผ๋กœ ์ž‘์—…์„ ์ฒ˜๋ฆฌ )

⇒ ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ ๊ฐ„์˜ ์—ฐ๊ฒฐ๊ณ ๋ฆฌ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์„œ๋ฒ„์˜ ํ™•์žฅ์„ฑ ↑

 

Token์„ ์‚ฌ์šฉํ•˜๊ฒŒ ๋œ ์ด์œ ?

์˜ˆ์ „์˜ ๊ธฐ์กด ์ธ์ฆ ์‹œ์Šคํ…œ์—์„œ๋Š” ์„œ๋ฒ„ ์ธก์—์„œ ์œ ์ €๋“ค ์ •๋ณด ๊ธฐ์–ตํ•˜๊ณ  ์žˆ์—ˆ๋‹ค. (์„ธ์…˜)

→ ๋กœ๊ทธ์ธ ์œ ์ €์˜ ์ˆ˜ ๋Š˜์–ด๋‚˜๋ฉด ์„œ๋ฒ„ ๋žจ ๊ณผ๋ถ€ํ™” ๋ฌธ์ œ / ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ฑ๋Šฅ๋ฌธ์ œ / ์„œ๋ฒ„ ํ™•์žฅ ์–ด๋ ค์›€

Token : ์•”ํ˜ธํ™” ๋œ ์ •๋ณด ์˜ค๊ณ  ๊ฐ€๊ธฐ ๋•Œ๋ฌธ์— ๋ณด์•ˆ ์ธก๋ฉด์—์„œ ์•ˆ์ „ + ์„œ๋ฒ„์— ๋ถ€๋‹ด X

 

JWT ( JSON Web Token )

 

 JSON ํฌ๋งท์œผ๋กœ ํ†ต์‹ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์–ด๋–ค Client ์—์„œ๋“  Data ํ†ต์‹ ์— JSON ์ด์šฉํ•˜๋ฉด ํ† ํฐ ์‚ฌ์šฉ๊ฐ€๋Šฅ

 ๋งŽ์€ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด ( C, Java, Python, C++, R, C# ... ๋“ฑ) ์—์„œ ์ง€์›

 ์ž๊ฐ€ ์ˆ˜์šฉ์  : JWT ๋Š” ํ•„์š”ํ•œ ๋ชจ๋“  ์ •๋ณด ์ž์ฒด์ ์œผ๋กœ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ⇒ ๊ฒ€์ฆ๋œ signature ํฌํ•จ / ์‰ฝ๊ฒŒ ์ „๋‹ฌ ๊ฐ€๋Šฅ

 

 JWT ๊ธฐ๋ณธ ๊ตฌ์„ฑ

 — ํ—ค๋” ( Header ) : JWT ์›น ํ† ํฐ์˜ ํ—ค๋” ์ •๋ณด

            typ : ํ† ํฐ์˜ ํƒ€์ž…, JWT ๋งŒ ์กด์žฌ

            alg : ํ•ด์‹ฑ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ( HMAC SHA256, RSA ) ํ—ค๋”๋ฅผ ์•”ํ˜ธํ™” ํ•˜๋Š” ๊ฒƒ X → ํ† ํฐ ๊ฒ€์ฆ ์‹œ ์‚ฌ์šฉ

 

 — ์ •๋ณด( Payload ) : ์‹ค์ œ ํ† ํฐ์œผ๋กœ ์‚ฌ์šฉํ•˜๋ ค๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ๋‹ด๊ธฐ๋Š” ๋ถ€๋ถ„

 

 — ์„œ๋ช… ( Signature ) : Header ์™€ Payload ์˜ ๋ฐ์ดํ„ฐ ๋ฌด๊ฒฐ์„ฑ๊ณผ ๋ณ€์กฐ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•œ ์„œ๋ช…

              Header ์™€ Payload ์˜ ์ธ์ฝ”๋”ฉํ•œ ๊ฐ’์„ ํ•ฉ์นœ ํ›„, Secret ํ‚ค ์™€ ํ•จ๊ป˜ Header์˜ ํ•ด์‹ฑ ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ ์ธ์ฝ”๋”ฉ

 

 JWT ๊ตฌ์กฐ : [ Header Payload Signature ] ๊ฐ๊ฐ JSON ํ˜•ํƒœ์˜ ๋ฐ์ดํ„ฐ๋ฅผ base64 ์ธ์ฝ”๋”ฉ ํ›„ ํ•ฉ์นœ๋‹ค.

                   aaaaaaa.bbbbbbbb.cccccccc . ์„ ์ด์šฉํ•ด ํ•ฉ์นœ๋‹ค.

 

node.js ์—์„œ jsonwebtoken ๋ชจ๋“ˆ ํ™œ์šฉ

  • ์ฃผ์š” ๋ฉ”์†Œ๋“œ 

       jwt.sign(payload, secretKey, option)

            secretKey : ์ž„์˜์˜ ๋ฌธ์ž์—ด, ๋žœ๋ค์œผ๋กœ ๋งŒ๋“ค์–ด ์„œ๋ฒ„๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ์Œ

            option : ์•Œ๊ณ ๋ฆฌ์ฆ˜, Token ์œ ํšจ๊ธฐ๊ฐ„

 

       jwt.verify(token, secretKey)

//jwt ๋ชจ๋“ˆ๋กœ ๋งŒ๋“ค์–ด์„œ ํ™œ์šฉ
module.exports = {
  sign : function(_id) {
    const options = {
      algorithm : "HS256",
      expiresIn : 60 * 60 * 24 * 30 //30 days
    };
    
    const payload = {
      _id : _id
    };
    
    let token = jwt.sign(payload, secretKey, options);
    return token;
  },
  
  verify : function(token) {
    let decoded;
    
    try {
      decoded = jwt.verify(token, secretKey);
    }
    catch(err) {
      if(err.message === 'jwt expired') console.log('expired token');
      else if(err.message === 'invalid token') console.log('invalid token');
    }
    
    if(!decoded) {
      return -1;
    } else {
      return decoded;
    }
  }
};

 

 

    JWT ์ธ์ฆ ๊ณผ์ • 

  1. ํด๋ผ์ด์–ธํŠธ ๋กœ๊ทธ์ธ
  2. ๋กœ๊ทธ์ธ ์ •๋ณด ๋ฐ”ํƒ•์œผ๋กœ secret key ์ด์šฉํ•ด ํ† ํฐ ์ƒ์„ฑ
  3. ๋กœ๊ทธ์ธ ์„ฑ๊ณต ์‹œ, ํ† ํฐ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์คŒ
  4. ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์‚ฌ์šฉ์ž ์ •๋ณด๊ฐ€ ํ•„์š”ํ•œ api ์š”์ฒญํ•  ๋•Œ, token ๊ฐ™์ด ๋ณด๋‚ธ๋‹ค.
  5. token ์ •๋ณด ํ™•์ธํ•˜์—ฌ ์œ ํšจํ•œ์ง€ ํŒŒ์•…
  6. ๋“ค์–ด์˜จ ์ •๋ณด๋กœ ์–ป์€ ๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จํ•œ response ๋ณด๋‚ด์ค€๋‹ค.