본문 바로가기
타입스크립트로 함께하는 웹 풀 사이클 개발(React, Node.js)/TIL

웹풀사이클 24일차 - 인증과 인가

by 슈크림 붕어빵 2023. 12. 27.

인증과 인가

1. 인증 (=로그인) Authentication 

 

1-1 세션(Session) : 로그인이 되어있는 상태

  • 과정: 로그인 시 서버가 정보를 저장하고 안전한 번호를 생성하여 제공. 사용자와 서버는 해당 번호로 통신.
  • 장점: 보안이 상대적으로 우수.
  • 단점: 서버가 저장하므로 서버 저장 공간 필요, 상태 유지 어려움.


 

1-2 쿠키(Cookies)

  • 과정: 웹 서버가 생성하고 웹 브라우저가 저장하며, 다음 웹 서버 방문 시 쿠키를 통해 로그인 가능.
  • 장점: 서버 저장 공간 필요 없음, 상태 유지 용이 (HTTP/stateless, RESTful).
  • 단점: 쿠키가 브라우저에 저장되므로 보안이 상대적으로 취약.


 
1-3 JWT : Json Web Token


개념
Json 형태의 데이터를 안전하게 전송하기 위해 웹에서 사용하는 토큰
토큰: (인증용) 입장 가능한 유저 / (인가)관리자 권한or일반유저 권한 부여용
= 토큰을 가진 사용자가 증명을 하기 위한 수단
 
구성요소

  • Header: 토큰 암호화에 사용되는 알고리즘 및 토큰 타입 (예: JWT).
  • Payload: 사용자 정보 등.
  • Signature: Payload 값이 변경되면 전체 시그니처 값이 변경되므로 신뢰성 유지 가능.

.
 
장점

  • 보안에 강하다 (암호화가 되어있다.)
  • HTTP 특징을 잘 따랐다. stateless하다 => 서버가 상태를 저장하지 않는다.
  • 서버 부담을 줄여줄 수 있고.
     
    토큰을 발행하는 서버를 따로 만들어줄 수도 있음.
     

 
어떤 알고리즘인지 알고 서버에 치명적인 데이터를넣으려고 한다면? 이라는 의문을 가질 수 있다.
하지만 payload가 바뀐다면 아래 파란색 부분인 서명이 바뀐다. => 서명이 틀린 경우, 서버에서 받아주지 않기 때문에 그런 일은 발생하지 않는다. 
 
2. 인가 Authorization
같은 사이트 내에 관리자/고객에 따라 접근할 수 있는 페이지가 다르다. 
관리자든 고객이든 인증을 통해서 사이트에 가입된 사용자라는걸 증명하는 것이다. 즉, 인증 후에 페이지 접근 권한 있는가를 확인하는 것.
 

예시 
jwt로 인증/인가 하는 절차
 
=> 로그인 성공, 로그인 당분간 유지.
 

Synchronous Sign with default (HMAC SHA256) => 디폴트 알고리즘
 
JWT 토큰 만들어보기

https://www.npmjs.com/package/jsonwebtoken

 

jsonwebtoken

JSON Web Token implementation (symmetric and asymmetric). Latest version: 9.0.2, last published: 4 months ago. Start using jsonwebtoken in your project by running `npm i jsonwebtoken`. There are 26035 other projects in the npm registry using jsonwebtoken.

www.npmjs.com

var jwt = require("jsonwebtoken");
var token = jwt.sign({ id: "bsu0404" }, "shhhhh");

console.log(token);

 

암호화 payload와  PrivateKey을 넣어준다. 옵션으로 알고리즘을 설정하지 않으면 디폴트 알고리즘으로 만들어진다. 
 
결과

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE3MDM2NTEyMzV9.TBZjuyPk1u6mZP7dxrsW2ae-KNFlQ3r_MerA2N7PQAg

 
token 확인 1) - jwt 사이트에서 
 

jwt 사이트에서 인코드된 값을 넣어주면 header와 payload, signature 가 나온다. 
 
token 확인 2)  - 코드로 검증하기

let decoded = jwt.verify(token, "shhhhhh");

console.log(decoded);​

 
결과: 

 
{ foo: 'bar', iat: 1703651235 }
 

 

.env (environment: 환경변수 '설정값')

  •  개념

개발을 하다가 포트번호, 데이터베이스 계정, 암호키 등등 외부에 유출되면 안되는 중요한 환경변수를 관리하기 위한 파일
(깃허브에 올라가면 안되는 값)
 
https://www.npmjs.com/package/dotenv

 

dotenv

Loads environment variables from .env file. Latest version: 16.3.1, last published: 6 months ago. Start using dotenv in your project by running `npm i dotenv`. There are 38862 other projects in the npm registry using dotenv.

www.npmjs.com

 
.env는 최상위 폴더에 위치!

공식문서대로 대문자, snakecase로 써주면 좋을 것이다.

다른 파일에서 process.env.[이름]으로 사용한다. 

 

.env

PRIVATE_KEY = "shhhhhh" #JWT 암호키

 

jwt.js

var jwt = require("jsonwebtoken");
let dotenv = require("dotenv");

dotenv.config();

var token = jwt.sign({ foo: "bar" }, process.env.PRIVATE_KEY);

 

참고 - config() 함수는?

  • dotenv 라이브러리의 메서드로, 주어진 파일에서 환경 변수를 로드하고 현재 프로세스의 환경 변수에 추가함.
  • 즉, .env 파일에서 환경 변수를 로드하고 있음. => 이 파일에는 PRIVATE_KEY라는 환경 변수가 정의되어 있어서 jwt.sign 메서드에서 사용됨

 

 

쿠키에 토큰 담아주기

https://www.npmjs.com/package/cookie-parser

 

cookie-parser

Parse HTTP request cookies. Latest version: 1.4.6, last published: 2 years ago. Start using cookie-parser in your project by running `npm i cookie-parser`. There are 8524 other projects in the npm registry using cookie-parser.

www.npmjs.com

jsonwebtoken외부 모듈와 dotenv외부 모듈을 이용해 sign한 뒤 cookie-parser 외부 모듈을 이용해 cookie에 보내준다. 

///로그인
router.post(
  "/login",
  [
    body("email").notEmpty().isEmail().withMessage("email must be a string."),
    body("pw").notEmpty().isString().withMessage("pw must be a string"),
    validate,
  ],
  (req, res) => {
    let { email, pw } = req.body;

    let sql = `SELECT * FROM users WHERE email = ? `;

    conn.query(sql, email, function (err, results) {
      if (err) {
        console.log(err);
        return res.status(400).send();
      }

      let loginUser = results[0];
      if (loginUser && loginUser.pw == pw) {
        //토큰 발급
        const token = jwt.sign(
          {
            email: loginUser.email,
            name: loginUser.name,
          },
          process.env.PRIVATE_KEY
        );

        res.cookie("token", token);
        res.status(200).json({ message: `${loginUser.name}님 환영합니다.` });
      } else {
        res.status(403).json({
          message: "id 및 pw를 확인해주세요.",
        });
      }
    });
  }
);

 

참고

403서버에서 설정해 둔 권한과 맞지 않는 접속 요청이 들어오면 접근을 거부하고 접근거부 코드를 반환하는데, 이 때 뜨는 것이 바로 403 Forbidden이다.

 

Cookie 살펴보기

 

1. Value?

value에서 토큰값을 확인할 수 있다. 

 

2. Secure? 

네이버에서 상단 부분을 눌러보면 아래와 같이 인증서가 있고, 믿을만한 user인지 암호화하여 http프로토콜을 보내도록 한 것이 https이다. 이 경우는 secure가 true

 

3. httpOnly?

httpOnly(=API 호출만 허락): XSS 공격(프론트엔드 공격: 웹브라우저 js접근)

httpOnly가 true면 api로만 가능

res.cookie("token", token, {
    httpOnly: true,
});

이같이 cookie에 옵션을 추가하면 httpOnly옵션이 true로 바뀐다. 

 

발행인 추가하기, 만료시간 추가

발행인 - sign할 때 issuer를 추가

만료시간 - sign할 때 expireIn 추가

const token = jwt.sign(
          {
            email: loginUser.email,
            name: loginUser.name,
          },
          process.env.PRIVATE_KEY,
          {
            expiresIn: "5m",
            issuer: "sungeun",
          }
        );

 

jwt.io사이트에서 확인 가능하다. 

 

위와 비교해보면 payload에 iss에 발급자, exp에 만료시간이 추가된 것을 확인할 수 있다.