[Backend] 인증 / 보안 2 : Token, OAuth

0

기타

목록 보기
9/10
post-thumbnail

혹시나 잘못된 개념 전달이 있다면 댓글 부탁드립니다. 저의 성장의 도움이 됩니다

토큰 Token

  • 토큰 기반 인증(Token-based Authentication)
    : 서버는 인증된 유저에게 암호화한 토큰(사용자의 정보를 포함)을 발행하고, 클라이언트에서 데이터를 보관하다가 서버로 요청할 때 토큰 정보를 실어보내 인증하는 방식이다. 인증할 때마다 DB를 확인하지 않아도 되서 서버의 부담이 덜하다.
    cf. 세션 기반 인증은 토큰 기반 인증과 달리 서버에서 사용자의 정보를 저장한다.

JWT

JSON web token
토큰 기반 인증 방식 중 한 유형으로 사용자가 로그인하면 2가지 종류의 토큰을 발급해주고 이를 통해 유저를 인증

  • Access Token
    : 데이터에 접근하는 권한을 가진 토큰으로 짧은 유효기간을 가진다.

  • Refresh Token
    : 사용자의 편의를 위해 Access Token가 만료된 경우 다시 인증을 요구하는 대신 인증기간이 조금 더 긴 Refresh Token을 사용하여 재발급을 해준다.
    cf. 편의보다 보완이 더 중요한 경우 리프레시 토큰을 발행하지 않기도 한다.


JWT의 구조

. 을 기준으로 Header, Payload, Signiture로 구분

  • Header
    : 토큰의 종류와 암호화 알고리즘 방식에 대한 정보를 포함한다. JSON 객체를 base64 방식으로 인코딩한 값이다.
    cf. header에 정의된 알고리즘 방식은 signiture를 만들 때 적용하고, header와 payload의 JSON 객체를 인코딩하는 방식이 아니다.
    e.g. {"alg":"HS256","type":"JWT"} 를 인코딩한 값

  • Payload
    : 사용자의 정보가 담긴 부분으로 접근 권한과 개인정보 등이 포함된다. 디코딩이 쉬우므로 민감한 정보를 담는 것은 지양한다.
    e.g. {"sub":"someInformation","name":"qwer","iat":12345} 를 인코딩한 값

  • Signiture
    : 서버에만 저장된 비밀키(secret)를 덧붙여 인코딩한 Header, Payload을 다시 암호화 한 값이다. payload가 조작되어도 signiture까지 같기 어려우므로 서버에서 변조된 토큰임을 알아차릴 수 있다.
    cf. header 부분에 정의된 암호화 알고리즘을 적용한다.
    e.g. HMACSHA256(base64UrlEncode(header)+'.'+base64UrlEncode(payload), secret)


JWT 사용법

jsonwebtoken 공식문서

const jwt = require('jsonwebtoken')

// 토큰 생성 : 로그인할 때
// jwt.sign(payload, secretOrPrivateKey, [options, callback])
const token = jwt.sign({ foo: 'bar' }, 'shhhhh');

// 토큰 검증 : 사용자 정보 조회할 때 디코딩해서 Signiture와 비교해보고 조작되어있지 않은지 확인
// jwt.verify(token, secretOrPublicKey, [options, callback])
const decode = jwt.verify(token, 'shhhhh');


토큰 기반 인증 절차

  1. 클라이언트가 서버로 로그인 요청
  2. 아이디와 비밀번호가 일치하면 토큰을 생성하여 클라이언트로 전달
    • access + refresh token
  3. 클라이언트는 전달받은 토큰을 저장
    cf. Local storage, Session storage, Cookie 등에 저장
  4. 클라이언트가 Cookie에 토큰을 담아서 서버로 요청을 전달
    cf. HTTP 메세지의 header에 토큰을 담아서 보낼 수도 있다.
    {Authorization:"Bearer JWT_TOKEN"}
    요약 참조, 상세 참조
  5. 서버 측에서 전달받은 토큰을 해독하여 일치하면 요청에 대한 응답을 반환

토큰 기반 인증의 장점

  • 무상태성(Statelessness) + 확장성(Scalability)
    : 서버에서 저장할 필요없이 해독만으로 판단할 수 있으며, 다른 서버에서도 유저 데이터 공유가 필요없이 인증이 가능하다.
  • 암호화로 안정성 확보
  • 토큰 발급의 다양화
    : 서버에서 직접 토큰을 발급할 필요가 없으며, 토큰 생성용 서버, 다른 회사 등에서 발급도 가능하다.
  • 특정 권한만 부여 가능
    e.g. 사진 조회만 가능한 권한 부여


OAuth

사용자의 정보를 가진 웹에서 인증(Authentication)을 중개하는 방식의 프로토콜로 보안된 리소스에 접근 권한(Authorization)을 담은 토큰을 클라이언트에 발행하는 과정을 단순화 한 방식

  • 인증(Authentication) : 대상을 확인
  • 접근 권한(Authorization) : 원하는 정보를 얻을 수 있게 허용

e.g. 소셜 로그인 인증 방식
: 각 웹 사이트마다 가입할 필요가 없어서 민감한 개인정보가 노출될 위험이 적고, 권한 전달 여부를 재확인하는 등으로 보완에 이점이 많다.

OAuth 용어

역할

  • Resource Owner : 로그인을 시도하는 사용자
  • Client : 사용하려는 애플리케이션으로 유저를 대신하여 리소스 서버에 접근하는 대상
  • Resource Server : 사용자의 데이터를 가진 대상으로 리소스를 줄 수 있는 서버
  • Authorization Server : 리소스 서버가 액세스 토큰을 발급받는 서버로 인증을 관리하는 대상

개념

  • Authorization Grant : 클라이언트가 액세스 토큰을 얻기 위해 사용하는 자격 증명 방식
    e.g. Authorization code grant type, refresh token grant type, client credentials grant type, implicit grant type, resource owner credentials grant type 등
  • Authorization Code : 액세스 토큰을 발급받기 위해 필요한 코드
    cf. 생활코딩 OAuth 등록 방법 참조 : Client ID로 code를 받아오면 Client Secret과 code로 액세스 토큰을 받을 수 있다.
  • Access Token
    : 보호된 리소스에 접근할 때 사용되는 문자열로 된 인증 토큰
  • Scope
    : 토큰에 담긴 접근 권한으로 허용된 리소스의 범위

OAuth 인증 절차

  1. 로그인
  2. 앱(Client)은 Authorization Server로 접근 권한을 요청
  3. 권한 양도 허가 재확인
  4. 접근 권한이 담긴 토큰(Access Token) 발행
  5. 토큰과 함께 API 요청을 하고 응답을 받음

Authorization code grant type

액세스 토큰을 발급받기 위한 방식 중 하나로 Authoriation code를 통해 토큰을 얻는 방식

  • 보완성
    : 클라이언트에서 client-secret을 공유하고 액세스 토큰을 가져오는 것은 탈취 위험이 있으므로 client에서는 authoriation code만 받아오고 서버에 액세스 토큰 발급 요청을 진행한다.

Authorization code grant type 인증 절차

  1. 사용자(Resource Owner)가 앱(Client)에 로그인
  2. 클라이언트는 Resource Owner가 Authorization Server로 연결되게 리다이렉트
  3. 사용자는 Authorization Server에게 권한 양도를 요청
  4. Authorization Server는 Authorization Code를 클라이언트에 전달
  5. 클라이언트는 Authorization Server로 Authorization Code를 전달하고 접근 권한이 담긴 토큰(Access Token) 발급을 요청
  6. 코드와 정보들이 일치하면 Access Token을 클라이언트로 발급
  7. 클라이언트는 Resource Server로 토큰과 함께 API 요청을 전달
  8. Resource Server는 토큰을 확인하고 클라이언트로 요청에 대한 응답을 반환

Refresh token grant type

유효한 리프레시 토큰으로 만료된 액세스 토큰을 편리하게 재발급 받을 수 있는 방법
1. 사용자(Resource Owner)가 앱(Client)에 로그인
2. 클라이언트는 Authorization Server에 리프레시 토큰를 전달하여 새 액세스 토큰 발급을 요청
3. 리프레시 토큰을 검증 후, Authorization Server는 클라이언트로 액세스 토큰 재발급
4. 클라이언트는 Resource Server로 토큰과 함께 API 요청을 전달
5. Resource Server는 토큰을 확인하고 클라이언트로 요청에 대한 응답을 반환




참고

OWASP

The Open Web Application Security Project
전세계의 보안 전문가들이 웹의 보안에 대한 표준을 정의하고 이에 대해 기업과 개발자들에게 효율적인 정보를 제공하는 오픈소스 커뮤니티
cf. 2017-2021 OWASP TOP 10 : 보통 3년 주기로 10대 보안 취약점을 발표한다.


웹 공격의 종류

- SQL Injection

사용자의 입력값을 받는 input에 의도적으로 SQL을 삽입하여 데이터 베이스를 조작하는 공격 유형
-> 해커에 의해 DB의 데이터가 유출되거나, 조작 될 수 있음

// 일반적인 SQL 예시 : id에 해당되는 문자열을 입력받아서 사용할 경우
// 기대하는 입력 형태 : 사용자는 kimcoding 입력
SELECT * 
FROM users
WHERE auth='admin'
AND id='kimcoding';


//SQL Injection 예시 1: 해커는 ' OR '1'='1 입력
SELECT * 
FROM users
WHERE auth='admin'
AND id='' OR '1'='1'; // --> 올바른 아이디가 아니더라도 항상 조회 가능

//SQL Injection 예시 2: 해커는 '; DROP TABLES users;--' 입력
SELECT * 
FROM users
WHERE auth='admin'
AND id='';DROP TABLES users;--'; // --> 데이터 제거됨

cf. SQL(Structured Query Language, 구조적 질의 언어): 데이터를 관리하기 위해 사용하는 선언형 프로그래밍 언어

SQL injection 대응 방안

  • 입력(요청) 값 검증
    : 블랙리스트 방식(키워드를 막기)에는 한계가 있으므로 화이트 리스트 방식(접근 가능한 키워드를 지정)으로 대응한다. 해당 키워드가 들어오면 값을 치환할 수 있도록 구현한다.

  • Prepared Statement 구문 사용
    : 입력값을 단순 텍스트로 인식하도록 구현한다. 서버로 전달되기 전에 컴파일한다.

  • Error Message 노출 금지
    : 해커는 에러 메세지를 통해서 데이터 정보를 취할 수 있으므로, 에러가 발생한 SQL문과 에러 내용이 노출되지 않도록 별도의 에러를 핸들링한다.


- XSS

Cross-Site Scripting, 사이트 간 스크립팅
해커에 의해 추가된 악의적인 스크립트가 실행되어 서비스를 이용하는 사용자에게 피해를 입히는 공격

  • 공격 대상은 클라이언트
    : 스크립트를 심어놓은 페이지에 접근을 유도하거나 일반게시물에 스크립트를 추가해놓고 해당 글을 조회한 경우가 피해 대상이 된다. 스크립트에 의해 의도하지 않은 동작이 수행되거나 사용자의 쿠키 등의 정보를 탈취한다.

  • Stored XSS
    : 스크립트가 서버에 저장되어 있는 형태로 지속적(persistent) 기법이라고도 부른다. 공격자가 텍스트가 아닌 악의적인 스크립트를 담은 게시글을 올리면 사용자가 그 글을 조회할 때마다(html이 렌더링 될 때) 스크립트가 실행된다.

  • Reflected XSS
    : URL 파라미터에 스크립트를 넣는 방식으로 비 지속적(non-persistent) 기법이라고도 부른다. 공격자는 링크를 추가하고 http://find.com/search?q=<script>alear("공격!")</script>&x=0 처럼 해당 링크에 스크립트가 추가되어있는 형태이다. 검색 후 결과가 없을 때 "...에 대한 결과가 없습니다." 처럼 URL 파라미터를 HTML에서 사용하는 것을 악용한다.

XSS 대응 방안

  • 스크립트 태그의 입력을 막기

    • 입력값 확인 혹은 필터링 : 클라이언트 측에는 < > 같은 특수문자가 입력되지 않게 하거나, 서버 측에서는 들어온 값에 특수 문자가 있는지 검정한다.(클라이언트에서 사용자의 입력을 받는 곳에 innerHTML 대신 textContent 속성을 사용하여 필터링할 수 있다.)
    • 입력값 치환하기 : < > 를 HTML entitiy 로 변환하여 저장한다.
  • 쿠키를 httpOnly 로 설정하기확인하기
    : 스크립트로 쿠키 정보를 탈취할 수 없도록 옵션을 httpOnly 로 설정하면 사용자의 쿠키에 저장된 개인 정보 노출을 막을 수 있다. (자바스크립트 document.cookie 로 브라우저에서 쿠키를 조회할 수 없다.)

  • 쿠키에 민감한 정보 담지 않기

    • 민감정보를 서버에서 관리하기
    • 암호화 사용하기
      e.g. id대신 암호화한 uuid 처럼 단순한 정보도 암호화하여 전달한다.

- CSRF

Cross-Site Request Forgery
도메인이 다른 곳( "same-site"와 "cross-site" 참조 )에서 사용자의 요청을 조작(forgery)하는 것
다른 origin에서는 응답에 직접적으로 접근할 수 없기 때문에 사용자의 요청 자체를 수정하여 해커가 원하는 방식으로 응답할 수 있게 한다.
e.g. 이메일을 속의 링크를 누르면 나의 계좌에서 해커의 계좌로 송금되게 요청한다.

  • CSRF 공격을 하기 위한 조건
    • 사용자가 로그인했을 때, 쿠키에 유저의 정보가 담긴 경우
    • 해커가 예측가능한 순서로 요청이 진행되는 경우
      e.g. 로그인 상태를 유지한 경우, 해커가 어떤 요청을 전달하려고 했을 때 인증을 위해 다시 로그인을 진행해야한다면 CSRF 공격을 하기 힘들다.
      e.g. get 요청에서 URL에 사용자 정보가 담기거나 POST 요청의 payload에 사용자의 비밀번호를 담아 전달 하는 경우

CSRF 대응 방안

  • CSRF 토큰 사용
    : 서버 측에서 CSRF 공격에 보호하기 위한 문자열을 유저의 브라우저와 웹 앱에만 제공한다.
  • 쿠키 옵션에 sameSite 속성을 추가
    : 같은 도메인에서만 쿠키와 세션을 사용할 수 있도록 설정한다.

- Clickjacking

보이는 화면을 실제 동작과 다른 동작으로 인식하게 만들고, 사용자를 속여 클릭하게 만드는 공격
겉으로 보이기에는 문제가 없지만 <iframe> 태그가 HTML 화면 위에 레이어가 생기는 특징을 사용하여 사용자를 속인다.
e.g. 신뢰할 만한 사이트와 동일한 피싱 사이트이거나 SNS 좋아요 버튼인 것처럼 속인다.

Clickjacking 대응 방안

  • HTTP 메세지에 X-Frame-Options 추가
    : X-Frame-Options 의 설정값에 따라 <iframe> 의 렌더링 여부를 제한할 수 있다.
    MDN X-Frame-Options

  • HTTP 메세지에 콘텐츠 보안정책 적용
    : 컴퓨터 보안 표준인 CSP(Content Security Policy)는 웹사이트 소유자들이 승인된 콘텐츠의 출처(origin)을 선언할 수 있도록하여 악의적인 스크립트 등의 데이터 삽입 공격을 막는다.

0개의 댓글