S3 Unit 7. 인증/보안

나현·2022년 11월 10일
0

학습일지

목록 보기
36/53
post-thumbnail

💡 이번에 배운 내용

  • Section3. 사용자 친화적이고 안전한 Web App을 만들 수 있다.
  • Unit7. 인증/보안: HTTP의 무상태성을 유지하면서, 각각의 유저에 대한 인증과 여러 인증 방식에 대해 학습한다.

느낀점

이번 유닛은 정말정말 어려운데다 지난 번 유닛을 제대로 학습하지 않으면 과제 수행이 어려웠다.
그래서 지난 번 유닛부터 이번 유닛까지 공부를 하는데 평소보다 오래 걸렸다. 블로그 작성이 이렇게 밀린 건 처음이다. 개념도 더 봐야 한다!
무엇보다 과제를 하는데 처음으로 과제 해설 강의 듣기 전까지 완료하지 못했다.
아니 이럴수가...! 실제로 머리가 지끈거린다는 느낌을 체감해보았다. 굉장하다.
그래도 열심히 게으름피우지 않고 이렇게 블로깅도 했고, 과제도 마무리하였다.
정수리가 뜨거운지 만져봤는데 생각보다 뜨겁지 않아서 당황스럽지만 어찌저찌 마무리해서 참 다행이다!


키워드

Cookie, Cookie 옵션, axios, Session, hasing, Token, Access Token, Refresh Token, JWT, OAuth, Authorization Code, Authorization Server, Resource Server, Authorization Grant, Authorization Code Grant Type, Refresh Token Grant Type


학습내용

이번 유닛에서는 HTTPS의 작동방식과 여러 인증방식에 대해 학습했다.
학습한 인증방식은 아래와 같다.

  • Cookie
  • Session
  • Token
  • OAuth

Ch1. Cookie

쿠키는 서버에서 클라이언트에 쿠키를 보내 데이터를 저장하는 방법으로,
반대로 서버로 클라이언트의 쿠키를 가져와 데이터를 가져올 수도 있다.

쿠키에는 다음과 같은 특징이 있다.

  • 서버가 클라이언트에 특정한 데이터를 저장할 수 있다.
  • 데이터를 저장한 이후 특정 조건들이 만족되면 이 데이터를 불러올 수 있다.
    이 조건들은 아래처럼 옵션으로 표현할 수 있다.
const cookiesOption={
  domain: cookieyummy.com, 
  path: '/',
  secure: true,
  httpOnly: true,     
}

Cookie의 주 옵션

위에서 잠깐 살펴본 것처럼 쿠키에는 옵션이 있다.
서버에서 이 쿠키 옵션들을 지정하고 클라이언트로 쿠키를 처음 전송할 때 헤더에 Set-Cookie라는 프로퍼티에 쿠키를 할당하여 전송한다.
그 후 클라이언트에서 서버로 쿠키를 전송할 때 클라이언트는 헤더에 Cookie라는 프로퍼티에 쿠키를 할당하여 전송한다.
이 쿠키 옵션의 종류와 특징은 다음과 같다.

  • Domain
    이름 그대로 도메인 이름으로 서브 도메인, 세부 경로를 제외한 도메인이다.
    예를 들어 'www.myurl.com/mypage' 에서 서브도메인인 'www'와 세부 경로인 '/mypage'를 제외한 'myurl.com'이 도메인이라고 할 수 있다.
    이 도메인 옵션이 있으면 클라이언트는 쿠키의 도메인 옵션과 서버의 도메인이 일치해야만 쿠키를 전송한다.

  • Path
    Path는 위에서 언급한 세부 경로를 의미한다. 즉 서버가 라우팅할 때 사용하는 경로로 위의 예시에서 '/mypage'에 해당한다. 만약 세부 경로가 없다면 기본 경로는 '/'가 된다.
    만약 path 경로의 하위 경로가 있어도 쿠키를 서버에 전송할 수 있다. 즉
    path 옵션이 '/mypage'여도 '/mypage/profile'로 요청이 가능하다.

  • MaxAge or Expires
    쿠키의 유효기간에 대한 옵션이다.
    MaxAge는 쿠키가 유효한 시간을 초 단위로 설정한다.
    Expires은 클라이언트의 시간을 기준으로 쿠키의 유효기간, 즉 쿠키가 없어지는 시간을 지정할 수 있다.
    이 옵션이 없으면 쿠키는 브라우저 종료시 삭제된다.
    만약 이 옵션이 없다면 세션 쿠키(Session Cookie), 이 옵션이 있다면 영속성 쿠키(Persistent Cookie)라고 한다.

  • Secure
    프로토콜에 따른 쿠키의 전송 여부를 결정하는 옵션이다.
    옵션값이 true면 HTTPS를 이용하는 경우에만 쿠키를 전송할 수 있다.
    옵션값이 false거나 없다면 프로토콜에 상관없이 쿠키를 전송할 수 있다.

  • HttpOnly
    자바스크립트에서 브라우저의 쿠키에 대한 접근 여부를 결정한다.
    옵션값이 true면 자바스크립트로 쿠키에 접근이 불가능하다.
    기본값은 false로 이 때는 document.cookie를 이용해 자바스크립트에서 쿠키접근이 가능하다. (이러면 XSS 공격에 취약해진다.)

  • SameSite
    이름 그대로 서버와 클라이언트가 같은 사이트인지, 즉 동일 리소스 출처(🔗관련 포스트)에 관한 옵션이다. 때문에 Cross-Origin 요청과 관련이 있다.
    요청에서 사용한 메소드와 이 옵션(GET, POST, PUT, PATCH 등)의 조합을 기준으로 서버의 쿠키 전송 여부를 결정한다.
    옵션값은 다음과 같다.

    • Strict: Cross-Origin이 아닌 same-site 인 경우에만 쿠키를 전송
    • Lax: Cross-Origin 요청이면 GET 메소드에 대해서만 쿠키를 전송
    • None: 항상 쿠키를 전송. 다만 쿠키 옵션 중 Secure 옵션이 필요

쿠키를 이용한 상태 유지

서버는 클라이언트에 인증정보를 담은 쿠키를 전송하고, 클라이언트는 전달받은 쿠키를 서버에 요청과 같이 전송하여 무상태성의 인터넷 연결을 상태성으로 유지할 수 있다.
그러나 쿠키는 HttpOnly을 사용하지 않으면 자바스크립트를 이용해서 접근이 가능하고, 오랜 시간 동안 유지될 수 있기 때문에 쿠키에 민감한 정보를 담아서는 안된다.
만약 해커가 이 인증정보를 이용해 유저대신 서버에 요청을 보내면 서버는 의심하지 않고 인증된 유저의 요청으로 처리하게 된다. 게다가 이 정보를 또 해커가 탈취한다면 또다른 피해를 입게 된다.

Axios

Axios는 Promise API를 활용해 통신하는 HTTP 비동기 통신 라이브러리로 주로 브라우저, Node.js로 사용한다.
Axios는 Fetch API와 비슷한 역할을 하지만 사용이 훨씬 간편하고 추가적인 기능도 있다.

  • Fetch API와 Axios 차이점
AxiosFetch API
설치가 필요O
(써드파티 라이브러리)
설치 필요X
(빌트인 API)
JSON데이터 형식으로 자동 변환.json() 메서드를 사용해야 함

Axios 사용법

Axios는 위에 언급한대로 별도의 설치가 필요하다.
npm install axios 을 터미널에 입력하여 설치한다.

기본 원리는 fetch API와 같으므로 GET 요청 사용법만 알아보고자 한다.

axios.get("url"[,config])

이런 식으로 get메서드를 사용한 요청이 가능하며
첫번째 인자에는 url주소(필수), 두번째 인자에는 요청 시의 옵션(필수 아님)을 작성한다.


Ch2. Session

세션 기반 인증에 대해 로그인과 로그아웃 중심으로 알아보고자 한다.

세션기반 인증 (Session-based Authentication) - 로그인

로그인시 사용자의 인증 정보를 저장하고, 그 후 인증된 사용자가 어떤 식으로 웹사이트를 이용하는지 알아본다.

사용자가 만일 정확한 아이디와 비밀번호를 입력했다면, 서버는 인증(Authentication)에 성공했다고 판단할 것이다.
이후에는 클라이언트에서 인증을 필요로 하는 작업(장바구니에 물품 추가 등)을 요청할 경우, 서버가 해당 사용자가 인증에 성공했을 알고 있기 때문에 매번 로그인할 필요가 없다.
그리고 이 인증에 따라 리소스의 접근 권한이 달라진다.

이 과정을 정리하자면 아래와 같다.

  • 서버는 사용자가 인증에 성공했음을 알고 있어야 한다.
  • 클라이언트는 인증 성공을 증명할 수단을 갖고 있어야 한다.
  • 사용자가 인증에 성공한 '상태'는 '세션'이라고 한다.
  • 서버는 저장소에 이 세션을 저장한다.
  • 세션에는 각 세션을 구분할 수 있는 세션 아이디가 있다.
  • 클라이언트에 이 세션 아이디를 전달한다.
  • 클라이언트에서 이 세션 아이디를 저장하며, 이것으로 인증 성공을 증명한다.

이후에 만약 클라이언트에서 요청을 할 때 이 세션 아이디를 서버에 전달하고, 서버는 저장소에 세션이 있는지 확인하여 접근 여부를 판단한다.
이 때 만약 쿠키에 세션 아이디가 없다면 서버는 해당 요청이 인증되지 않았다고 응답한다.

세션기반 인증 (Session-based Authentication) - 로그아웃

클라이언트에 세션 아이디가 담긴 쿠키가 저장되어 있고 서버는 세션을 저장하고 있다. 서버는 이 세션 아이디로만 인증 여부를 판단한다.
따라서 만약 쿠키가 탈취된다면 세션 아이디가 저장되어 있으므로 해커가 사용자인척 요청할 수 있다. 서버에서는 인증된 사용자의 요청이라고 판단하기 때문에 는 이를 방지하기 위해서 필요없을 때는 로그아웃을 해야 한다.

로그아웃 과정에 대해 정리하자면 다음과 같다.

  • 서버는 세션 정보를 삭제해야 한다.
  • 클라이언트: 쿠키를 갱신해야 한다.
  • 서버는 클라이언트의 쿠키를 임의로 삭제할 수 없으므로, set-cookie로 세션 아이디의 키값을 무효한 값으로 갱신하여 클라이언트에게 쿠키를 전송한다.

express-session

Node.js에는 세션을 대신 관리해 주는 모듈로 express-session 이라는 모듈이 있다.
express-session은 세션을 위한 미들웨어로, express 서버에서 쉽게 세션을 다룰 수 있도록 해준다.
아래처럼 세션의 옵션을 지정할 수 있다.

const express = require('express');
const session = require('express-session');

const app = express();

app.use(
  session({
    secret: '@codestates',
    resave: false,
    saveUninitialized: true,
    cookie: {
      domain: 'localhost',
      path: '/',
      maxAge: 24 * 6 * 60 * 10000,
      sameSite: 'none',
      httpOnly: false,
      secure: true,
    },
  })
);

자세히 보면 쿠키 옵션과 비슷하나 세션은 secret 옵션의 비밀키를 이용해 암호화해 세션 아이디라는 것을 생성한다. 그리고 이것을 클라이언트에게 쿠키로 전송한다.
위에서 로그인 과정에서 언급한대로 쿠키로 전송된 세션 아이디는 고유한 세션 객체를 가지며 서버에 저장된다. 이 세션 객체는 사용자별로 독립적으로 생성되기에 각 사용자의 데이터를 저장할 수 있다.
그리고 이 세션 아이디가 있기에 클라이언트에 유저의 개인정보를 담지않아도 서버가 이 세션 아이디로 사용자의 인증여부를 판단할 수 있다.

위에서 설명한 세션 객체는 req.session으로 접근할 수 있으며 세션에 임의의 데이터를 저장하거나 불러올 수 있다.
세션 객체에 값을 할당하는 방법, 값을 불러오는 방법, 세션을 파괴하는 방법은 다음 링크를 참고하면 된다.

🔗 GitHub: express-session


Ch3. Token

이번 챕터는 인증방식 중 하나인 토큰에 대해 설명한다.
토큰 인증방식에는 해싱이라는 암호화 방식이 필요하다.
먼저 아래와 같이 해싱부터 살펴본다.

해싱 (Hashing) - 해시 함수

해싱은 암호화 방식 중 하나로 암호화, 복호화 중 암호화만 가능하다.
해시 함수(Hash Function)을 사용하여 해싱 암호화를 진행하는데, 해시 함수는 다음과 같은 특징을 갖는다.

  • 항상 같은 길이의 문자열을 리턴한다.
    서로 다른 문자열에 동일한 해시 함수를 사용하면 다른 결과값이 나오며,
    동일한 문자열에 동일한 해시 함수를 사용하면 항상 같은 결과값이 나온다.
    아래는 대표적인 해시 함수중 하나인 SHA1에 특정 입력 값을 넣었을 때 어떤 결과가 리턴되는지 보여주는 예시다.

|비밀번호|해시 함수(SHA1) 리턴 값|
|‘password’|‘5BAA61E4C9B93F3F0682250B6CF8331B7EE68FD8’|
|‘Password’|‘8BE3C943B1609FFFBFC51AAD666D0A04ADF83C9D’|
|‘kimcoding’|‘61D17C8312E8BC24D126BE182BC674704F954C5A’|

🔗 온라인 SHA1 해시 생성기 사이트

  • 솔트(Salt)
    항상 같은 결과값이 나오므로 함수의 입력값을 알아낼 수 있도록 기록해놓은 레인보우 테이블이라는 것이 존재한다. 만약 입력값이 이 레인보우 테이블에 기록되었다면 해싱의 의미가 없으지므로 보안상 위험하다.
    때문에 여기에 활용할 수 있도록 솔트(Salt)라는 것이 존재하는데, 말 그대로 소금 치듯이 해시 함수의 입력값에 임의의 값을 더하는 것이다. 그러면 입력값과 솔트 둘 다 알아야 하므로 유출 위험이 좀 더 줄어들게 된다.

해싱의 목적

해싱은 입력한 데이터가 어떤 값인지 알 수는 없지만 입력한 데이터와 출력한 데이터가 동일한 값인지 아닌지는 확인할 수 있다. 때문에 복호화가 불가능한만큼 보안이 어느정도 보장되면서 동일한 값 여부는 확인할 수 있으므로 사용한다.
예를 들어 사용자가 입력한 아이디, 비밀번호를 암호화해서 전송하고, 이 상태에서 입력한 비밀번호가 맞는지만 확인되면 따로 복호화를 하지 않아도 되고 중간에 탈취될 위험도 없다.
심지어 서버에서 사용자의 개인정보를 몰라도 올바른 정보인지 확인이 가능하다는 장점이 있다.

토큰기반 인증 (Token-based Authentication)

토큰은 해싱처럼 암호화된 정보가 담겨 서버와 클라이언트가 주고받을 수 있는 것을 의미한다.
이름 그대로 어떤 행사나 이벤트에 입장이 가능하다고 증명되는 토큰과도 같은 것이다.
이런 토큰기반 인증 중 가장 대표적인 것으로 JWT (JSON Web Token)가 있다.
이 토큰에 암호화된 유저 정보를 담아 클라이언트에 저장할 수 있다.

JWT의 종류

JWT는 종류로 엑세스 토큰(Access Token), 리프레시 토큰 (Refresh Token)이 있다.
이 두가지 종류의 토큰으로 접근권한 부여, 인증 등에 사용한다.

  • 엑세스 토큰: 사용자 정보 등 리소스에 접근할 수 있는 권한을 부여한다.
  • 리프레시 토큰: 기간이 만료된 엑세스 토큰을 발급받는데 사용한다.

만약 사용자에게 권한을 부여하거나 사용자 인증을 해야 한다면 엑세스 토큰을 발급한다. 이 엑세스 토큰은 기간이 지나면 만료된다.
만약 로그인 유지 등 엑세스 토큰을 유지하고자할 때는 엑세스 토큰과 리프레시 토큰 둘 다 발급한다. 그래서 엑세스 토큰의 기한이 만료되면 리프레시 토큰으로 엑세스 토큰을 재발급받아 엑세스 토큰의 유효기간을 늘릴 수 있다.(ex) 로그인 유지)

JWT 구조

JWT는 Header, Payload, Signature로 구성된다.

  • Header: 어떤 종류의 토큰이며(JWT), 어떤 알고리즘으로 시그니처를 암호화할지 json 형태로 담겨 있다. 이 JSON 객체를 base64 방식으로 인코딩한다.
{
  "alg": "HS256",
  "typ": "JWT"
}
  • Payload: 유저의 정보와 접근 권한이 담겨 있다. 너무 민감한 정보는 담지 말아야 하며 마찬가지로 base64 방식으로 인코딩된다.
{
  "sub": "someInformation",
  "name": "phillip",
  "iat": 151623391
}
  • Signature: 해싱에서 배운것처럼 서버의 비밀키(salt)와 헤더에 지정한 알고리즘으로 위의 인코딩된 header, payload를 해싱한다.
    만약 암호화 방법 중 HMACSHA256 알고리즘을 사용한다면 Signature는 아래와 같이 해싱한다.
HMACSHA256(base64UrlEncode(header) + '.' + base64UrlEncode(payload), secret);

위에서 설명한 토큰은 다양한 방식으로 담을 수 있다. 쿠키에 담거나 HTTP 헤더에 담을 수도 있고 엑세스 토큰, 리프레시 토큰을 각각 따로 담을 수도 있다.

토큰기반 인증의 장점

  • 무상태성(Statelessness), 확장성(Scalability)을 가진다: 서버는 클라이언트에 대한 정보를 저장할 필요없이 일치 여부만 확인한다.
  • 안전하다: 암호화한 토큰을 사용하며 암호화 키가 노출될 가능성이 낮다.
  • 어디서나 생성 가능하다. : 토큰 생성용 서버를 만들거나, 아웃소싱이 가능하다.
  • 권한 부여에 용이하다. : 토큰의 Payload에 어떤 정보에 접근 가능한 지 정할 수 있다.

Ch4. OAuth

OAuth 란?

직접 작성한 서버가 아닌 인증을 중개하는 외부 서버에서 인증을 받는 매커니즘을 뜻한다. 사용자 리소스가 저장된 서버가 따로 있기도 한다.
대표적으로 소셜 로그인 서비스 작동방식이 있으며 주로 OAuth 2.0를 바탕으로 구현된다.
서버에서 사용자 정보를 새로 저장하지 않고 이미 사용자 정보를 가진 외부 서버와 인증을 처리하는 외부 서버를 활용해 사용자 인증을 받는다.
이 OAuth 매커니즘을 활용하면 사용자 입장에서 새로운 서비스에 가입하지 않아도 서비스 이용이 가능하며, 서버는 새로 데이터를 저장하거나 기존 사용자를 관리할 필요없이 사용자에게 서비스할 수 있다.
또한 사용자 데이터 서버, 인증 서버를 기존의 것을 활용하므로 검증되지 않은 새로운 앱에서 정보가 유출될 확률이 낮아진다.

OAuth 관련 용어

OAuth 매커니즘을 이해하기 위해선 아래인 용어를 알아야 한다.

  • Resource Owner: 사용자. 정보 제공자
  • Client: Resource Owner를 대신해 리소스에 액세스하는 앱
  • Local Server: Client의 요청을 수락하고 응답할 수 있는 서버
  • Resource Server: 사용자의 정보를 저장하고 있는 서버
  • Authorization Server: 인증 서버(Access Token을 발급)
  • Authorization Grant: Client가 Access Token을 얻는 방법.
    • Authorization Code Grant Type: 엑세스 토큰을 얻는 방법
    • Refresh Token Grant Type: 리프레시 토큰으로 엑세스 토큰을 얻는 방법
  • Authorization Code: Authorization Grant에서 Access Token을 발급받기 위한 Code
  • Access Token: Resource Server에 접근가능한 인증 토큰.
  • Refresh Token: Access Token이 만료될 시 Access Token을 재받급받을 수 있는 토큰

OAuth 인증 과정: Authorization Code Grant Type

OAuth 인증 과정, 즉 Grant Type에 대해 알아본다.
그 중에서도 과정이 좀 더 복잡한 Authorization Code Grant Type 에 대해 좀 더 알아본다.
그 과정은 아래 이미지와 같다.

Authorization Code Grant Type은 Authorization Code를 받고, 이를 활용해 Access Token을 받는 방식이다.
위 이미지는 소셜 로그인 방식을 나타낸 것으로 각 흐름 중 숫자는 순서를 나타낸다.
번호로 매겨진 각 과정에 대해 자세히 정리하면 다음과 같다.

  1. 사용자 액션 :
    사용자가 사이트에 접속하여 소셜 로그인 버튼을 클릭한다.
  2. Authorization Code 요청 :
    클라이언트(Client)가 인증 서버(Auth Server)로 인증을 요청한다. 경우에 따라 인증 페이지로 이동하며 클라이언트 아이디나 인증 키 등이 필요하다.
  3. 인증서버 -> 클라이언트로 Authorization Code 전달 :
    인증되었다면 인증 서버에서 Authorization Code를 클라이언트로 전달한다.
  4. 클라이언트 -> 로컬 서버로 Authorization Code 전달 :
    인증받은 코드를 클라이언트가 로컬 서버로 전달한다.
  5. Access Token 요청 :
    로컬 서버는 클라이언트에게 받은 Authorization Code를 가지고 인증 서버에 엑세스 토큰(Access Token)을 요청한다.
  6. Access Token 전달 :
    인증 서버는 Authorization Code를 확인하고 인증되었다면 엑세스 토큰을 로컬 서버로 전달한다.
  7. 유저 정보 요청 :
    로컬 서버는 인증 서버에게 전달받은 엑세스 토큰을 가지고 리소스 서버(Resource Server)에 있는 사용자 정보를 요청한다.
  8. 리소스 서버 -> 로컬 서버로 유저 정보 전달 :
    리소스 서버는 엑세스 토큰을 확인하고 인증되었다면 로컬 서버로 요청받았던 사용자 정보를 전달한다.
  9. 로컬 서버 -> 클라이언트로 유저 정보 전달 :
    로컬 서버는 리소스 서버로부터 전달받은 사용자 정보를 클라이언트에 전달한다.

위와 같이 Authorization Code Grant Type을 로그인을 예시로 들어 살펴보았다.
Refresh Token Grant Type의 경우는 5번의 과정만을 수행하며, 이 때 로컬 서버는 Authorization Code 대신 리프레시 토큰을 이용하여 엑세스 토큰을 요청한다.
인증 서버는 이 때 엑세스 토큰을 재발급하여 로컬 서버에 전달해준다.


profile
프론트엔드 개발자 신나현입니다. 시리즈로 보시면 더 쉽게 여러 글들을 볼 수 있습니다!

2개의 댓글

comment-user-thumbnail
2022년 11월 16일

잘보고 가용 !!!!!!!

1개의 답글