TIL #12 // Hashing, Authentication(Cookie & Session& Token)

이윤주·2020년 2월 16일
0

보통 인증과정을 거치지 않고 정보들을 얻는다면?

  1. client에 email에 관련된 정보를 서버를 요청
  2. 서버에서 정보를 DB에 가져가 response하고 client가 가져감

여기서 문제점: 누구나 email을 알고 있다면 정보를 가져갈 수 있음

아! 그렇다면 비밀번호를 요청하자
1. client에 email에 관련된 정보를 비밀번호를 정하고 서버를 요청
2. 서버에서 email과 비번 정보를 DB에 보냄
3. 그 정보들을 비교하고 정상적으로 맞다면 DB에서 다시 해당 email을 가지고
서버에게 전달해 서버는 response하고 client가 가져감

여기서 문제점: DB에 접근 할 수 있다면 바로 비밀번호가 뚫림

이! 비밀번호를 데이터베이스에 암호화하여 저장하자

Encrypton이란?
암호화는 일련의 정보를 임의의 방식을 사용하여 다른 형태로 변환하여 해당 방식에 대한 정보를 소유한 사람을 제외하고 이해할 수 없도록 '알고리즘'을 이용해 정보를 관리라는 과정

Hashing

[hash, salt]
[crypto 모듈을 사용한 암호화]
[쉽게 알아보는 서버 인증]
보통 웹앱에서 사용자 정보인 비밀번호를 DB에 저장할 때 보안을 위해 해싱 알고리즘을 이용하여 암호화(Encryption)시켜 비밀번호를 보호한다. 해싱이란 어떠한 문자열에 '임의의 연산'을 적용하여 다른 문자열로 변환하는 것을 말한다.

Hashing의 특징, 조건

  • 단방향 암호화 기법이기 때문에 복호화가 불가능하다.
  • 암호화 할 문자가 한글자만 달라도 값이 완전히 달라진다.
  • 모든 값에 대해 해시 값을 계산하는데 오래걸리지 않아야한다
  • 최대한 같은 해시 값을 피해야하며, 모든 값은 고유한 해시 값을 가진다
  • 아주 작은 단위의 변경 이라도 완전히 다른 해시 값을 가져야 한다.
  • 대표적인 hash 알고리즘 - sha512
    (MD5나 SHA1 방식은 알고리즘이 뚫렸다 함 절대 사용 x)

Crypto

crypto란 node.js의 내장 모듈로서 암호화와 관련된 일을 처리한다.

여러가지 Hash기반 Crypto 기법들

CreateHash

const crypto = require('crypto');// 모듈
    
crypto.createHash('sha512'); // sha512 알고리즘
.update('hello') // hashing할 문자열(비밀번호)
// 'get coding' 이라는 문자열을 해싱하겠다는 의미. 
.digest('base64') // output type(표시할 인코딩 설정) 
// 해싱한 문자열을 base64로 인코딩하여 다이제스트를 반환한다.  
// 다이제스트란 해시를 통해 얻어낸 암호화된 값을 뜻한다.

Hmac

const crypto = require('crypto');// 모듈

crypto.createHmac('sha512', 'salt') // (알고리즘, salt값)
  .update('hello') // hashing할 문자열(비밀번호)
  .digest('hex') // output type(표시할 인코딩 설정) 

Salt

해싱의 한계를 극복하기 위해, 해시 함수를 여러 번 반복하여 적용하거나 솔트(salt)를 활용할 수 있다.

  • 기존 : (암호화 하려는 값) => (hash값)
  • Salt 사용 : (암호화 하려는 값) + (Salt 용 값) => (hash값)

crypto 모듈에서는 pbkd2(Password-Based Key Derivation Function 2)라는 비동기 메서드를 통해 솔트를 적용할 수 있다.

const crypto = require('crypto')
// password, salt, iteration, 바이트 길이, 알고리즘, 콜백을 인자로 받는다.
crypto.pbkdf2('hello', 'salt', 123456, 64, 'sha512'
//(비번, salt값, 해싱반복횟수, 바이트, 알고리즘)
  , (err, derivedKey)=> { // 콜백 (derivedKey: hashing한 값)
    if(err) {
      throw err
    };
    console.log(derivedKey.toString('hex')) 
    // hex로 인코딩한다.
})
  • 만약 솔트 값이 고정될 시 유출을 방지하기 위해 salt값을 랜덤하게 생성해야 한다. 이와 관련하여 crypto에서 사용할 수 있는 메서드가 바로 randomBytes이다
    (랜덤으로 생성된 솔트는 해싱된 값(derivedKey)와 반드시 함께 저장해야 한다)
const crypto = require('crypto');// 모듈

crypto.randomBytes(64, (err, buf)=>{ 
// 랜덤하게 생성된 버퍼를 base64를 통해 인코딩한다.
  const randomlyGeneratedSalt = buf.toString('base64') // 랜덤으로 salt 생성 
  crypto.pbkdf2('hello', randomlyGeneratedSalt, 123456, 64, 'sha512'
// (비번, 랜덤으로 salt 생성한 값, 해싱반복횟수, 바이트기링, 알고리즘)                
  , (err, derivedKey)=>{ // 콜백 (derivedKey: hashing한 값)
    if(err) {
      throw err
    }; 
    console.log(derivedKey.toString('hex')) 
  })
})

Authentication(인증)

쿠키는 사이트를 이용할때 브라우저에 저장되는 내용

  • 서버가 사용자의 위치에 정보를 저장하고 불러올수 있는 수단(서버와 클라이언트가 대화하는 수단)
  1. 특정 호스트에서 생성된 쿠키는 이후 모든 요청마다 서버로 다시 전송
  • 브라우저가 서버와 연결이 됐을때 자동적으로 쿠키가 생성이 되어 해당 쿠키가 있지 않을경우
    -> data를 response할 때 쿠키를 담아서 보내준다.
    -> 그 이후 클라이언트가 서버에 요청을 보낼 때 따로 액션을 취하지 않아도 쿠키가 http에 담아져서 보내진다.
  1. 이름, 값, 만료 날짜, 경로 정보로 구성

Session

쿠키에 저장하기 곤란한것들은 세션에 저장된다 생각하면 된다. 세션은 쿠키를 기반으로 한다.

  • 서버와 클라이언트의 연결이 활성화 된 상태
  1. 서버가 Client에 대해 유일한 ID를 부여하여 서버 측에서 관리
    어떤 브라우저가 그 세션을 관리한다 하였을 때 클라이언트가 서버를 접속한다
    서버에서 자체적으로 클라이언트에 대해 판단하여 처음 만난 클라이언트면 id를 부여한다
  2. 일반적으로 이 유일한 Client ID가 서버에서 존재하는 상황을 Session이라고 칭한다
    즉 브라우저와 서버가 연결되어 있을때 그때만 Client Id가 존재한다 (페이지 꺼버리면 client ID 지워짐)
  3. 각 Client ID의 Session 객체 마다 Data를 관리 할 수 있다
  4. 사용자의 정보 중 보안상 중요한 데이터는 Session에서 관리한다.
    if) 클라이언트(cookie라든지)쪽에서 관리한다면 상대적으로 노출되기 쉬움 따라서 서버쪽에서 관리해야 더 안전
  5. 쿠키를 보고 서버가 저장소를 만들어서 세션이라는 저장소에(서버가 켜져있는 동안에) in memory로 클라이언트에 저장

    Token

쿠키는 브라우저가 무조건 가져야하는것(자동적으로 발생) 그러나 토큰은 무조건적은 아니다.. 보완성 있는 쿠키?

  • 인증을 위해 사용되는 암호화 된 문자열
    -> 즉 어떤 정보들을 해싱해서 클라이언트와 서버를 왕복한다
  1. Http 통신의 Stateless 특징과 알맞다
    기본적으로 http통신은 연결된 상태 일때만 정보를 교류할 수 있게 되어있다.
    if) 웹브라우저를 껐을때 즉 서버에 연결되어 있지 않으면 교류 하지 않고 그때 생긴 정보를 파기한다
    -> 즉 유저의 상태를 관리하지 않아도 된다
  2. 유저의 인증 정보를 서버나 세션에 담아두지 않는다
    그냥 토큰에 대해서 토큰을 가지고 있으면 그거로 판별가능
    -> 즉 세션을 생성해서 브라우저를 담아주지 않아도 된다
  3. 유저의 활성화 여부를 신경쓰지 않고 넘겨진 요청에 담겨진 Token의 정합성만을 확인
  4. 서버에서 클라이언트의 상태 정보를 저장하지 않고 클라이언트에서 넘겨지는 요청만으로 작업을 처리하게 된다. 이런 경우 클라이언트 상태관리에 관한 비용이 없기 때문에 서버의 확장성이 높다.
  5. 토큰은 클라이언트 사이드에서의 인증수단 클라이언트에서 가지고 있음
    -> 즉 토큰이 유효한지 안하는지만 활용(토큰은 서버가 발행해서 줌) 서버가 만들어주는데 토큰을 클라이언트에게 준다.
  6. 토큰은 서버가 좀더 그 유저의 권한에 맞게 주는 것
  7. 토큰은 만료기간동안 무한정하게 정보를 빼갈 수 있어서 위험
  8. 토큰의 장점: 다른 사이트의 정보를 기반으로 로그인을 가능


0개의 댓글