항해 1주차를 마무리하면서

안대륜·2022년 3월 13일
post-thumbnail

정말 간만에 너무 열심히 살아본 한주였다... 이렇게 14번만 더하면 된다 ㅎㅎ.. 그럼 한주동안 배운 WIL과 API에 대해서 회고를 해보자면 코딩을 알기전에는 홈페이지를 이용하면서 로그인과 회원가입을 할때 그냥 당연히 되야하는게 아니야 ? 라고 생각했었는데 직접해보고나니 정말 만만치 않은작업이라는것을 깨닫게 되었습니다 그리고 이 로그인상태를 유지하는것도 간단한게 아니라는것을 깨닫게 되면서 그동안 이용하였던 서비스들에대해서 감사하게되었고 세상을 좀 더 세부적으로 넓게 보는 시각을 가지게 된거같습니다


Authentication(인증) : 로그인

Authorization(인가) : 로그인후의 허가된 활동들(로그인이 유지되는 상태에서 일어나는 일)

먼저 기존의 많이 사용되어온 세션방식

  • 사용자가 로그인에 성공하면 ,서버는 "세션 표딱지" 란걸 출력함(영환관 티켓같은것)
    이걸 쭉 찢어서 반쪽은 사용자의 브라우저로 보내고 다른 반쪽은 자기메모리(책상)에 올려놓는거임 경우에 따라서는 하드디스크(서랍) 에 넣거나 데이터베이스(창고) 에 넣어놓기도 함
    뭘 넣거나 꺼내는 작업이 얼마나 가볍고 빠르냐에 따라서 메모리는 책상 ,하드는 서랍, 데이터베이스는 창고에 비유한거임
    브라우저가 이표를 Session ID라는 이름의 쿠기로 저장하고(쿠키란게 브라우저에 저장되는 정보) 이 브라우저는 앞으로 다음 사이트에 요청을 보낼때마다 이 표딱지를 실어보냄
    이제 요청에 이 표 반쪽 , 세션 아이디란게 실려오면 서버는 그거를 메모리에서 맞는 짝이 있는지 찾아보고 있으면 인가를 해주는것임
  • Session ID를 사용해서 어떤 사용자가 서버에 로그인 된 되어있음이 지속되는 상태를 " 세션 "이라고 한다
  • 즉 어떤 사용자들이 현재 로그인해있는지를 가지고 서버가 표반쪽들을 어디 둬서 기억을 해두고 있는게 세션임

세션의 허점

  • 메모리에 세션 표반쪽들을 올려놓으면 사용자가 동시에 많이 접속을 하면 메모리가 부족해짐
    그리고 이 메모리는 서버에 문제가 있어서 꺼져버리거나 하면 휘발성이라서 죄다 날라가버림
  • 그래서 에러가 나타나서 책상을 엎어버리면 즉 서버가 재부팅되어야 하는 상황이 오면 메모리에 있던것들은 전부 날아감
  • 이렇게 되면 사용자들은 전부 로그인이 튕겨서 다시 로그인을 해야하고 ,
    하드(서랍)에 넣어놓기에는 매 요청마다 하드(서랍)을 열고 닫고 해야해서 아무래도 메모리에서 바로바로 하는 것보다는 좀 느려짐
    더 골치아픈 경우는 서비스가 어느정도 규모가 있어서 서버를 여러대를 두고 운영을 할때 (서버가 여러대가 있다는것은 서버들 여러명이가 각자 책상이랑 서랍을 두고 일을 하고 있고 손님들 요청이 들어오면은 그 요청들을 갖다가 그 여러 서버들 사이에 분산을 해서 로드 바란싱을 해주는건데 만약 로그인은 1번서버에 연결돼서 하고 그다음에 이메일 페이지로 가는 요청은 3번 서버한테 가면은 3번 직원 책상이나 서랍에는 그 사용자 표 반쪽이 없으니까 세션 유지가 제대로 안되는거임
    그렇다고 사용자의 요청이 각자 할당된 서버로만 보내지게 하는것도 되게 번거롭고 까다로움
  • 다른방법으로는 데이터베이스(공용창고)서버에 넣어두거나(대신 이렇게 하면 속도가 많이 느려짐) 더 흔히는 레디스나 MemCached같은 메모리형 데이터베이스 서버 즉 길다란 공용 책상을 따로 둬서 그위에다 올려두기도 함 (물론 이 책상이 엎어지는것도 리스크임)
  • 서버가 복잡한 구성과 환경에서 어떤 상태를 기억해야된다는게 되게 설계하기가 머리아픈거임

그래서 이런 부담없이 이 인가를 구현하기위해 고안된게 "토큰방식"인 JWT임

JWT (Jason Web Token)

로그인과 회원가입에 이용 되는 JWT 는 JSON Web Token의 약자로 전자 서명 된 URL-safe (URL로 이용할 수있는 문자 만 구성된)의 JSON입니다.
전자 서명은 JSON 의 변조를 체크 할 수 있게되어 있습니다.
JWT는 속성 정보 (Claim)를 JSON 데이터 구조로 표현한 토큰으로 RFC7519 표준 입니다.
JWT는 서버와 클라이언트 간 정보를 주고 받을 때 Http 리퀘스트 헤더에 JSON 토큰을 넣은 후 서버는 별도의 인증 과정없이 헤더에 포함되어 있는 JWT 정보를 통해 인증합니다.
이때 사용되는 JSON 데이터는 URL-Safe 하도록 URL에 포함할 수 있는 문자만으로 만듭니다.
JWT는 HMAC 알고리즘을 사용하여 비밀키 또는 RSA를 이용한 Public Key/ Private Key 쌍으로 서명할 수 있습니다.

jwt를 사용하는 서비스에서는 , 사용자가 로그인을 하면 토큰(인코딩처럼 암호화된 데이터)이라는 표를 세션과다르게 찢어서 주지않고 그냥준다 (서버가 뭔가를 기억하고 있지 않는다는것)

이토큰 암호는 마침표 (.) 으로 끊어져서 세 부분으로 나뉘는데 각각 header , payload , vertify signature로 구분됨

Ex) {header}.{payload}.{signature}

위인코드를 디코드 한값

지금부터 (1번) header , (2번) payload , (3번) verify signature 라고 해보자

  • 그 중 먼저 payload에대해서 알아보자면 이걸 Base64로 디코딩해보면 JSON형식으로 여러 정보들이 들어있음

  • 이 토큰을 누가 누구에게 발급했는지 , 이토큰이 언제까지 유효하고 서비스가 사용자에게 이 토큰을 통해 공개하기 원하는 내용 (사용자의 닉네임 서비스상의 레벨, 관리자여부등)처럼 서비스측에서 원하는대로 담을수있다 이렇게 토큰에 담긴 사용자 정보등의 데이터를 Claim이라고한다.

  • 즉 사용자가 로그인을 하고나서 받는 토큰에 이정보들이 클레임이라는걸로 실려나온다는 거고
    이게 이후 요청들마다 이번에는 사용자로부터 서버한테 보내지고 , 사용자가 받아서 갖고 있는 토큰 자체에 이런 정보들이 들어있으면은 서버가 요청마다 일일이 데이터베이스에서 찾아봐야할것들이 줄어든다

  • 하지만 특별한 암호화도 아니고 Base64로 인코딩 돼있는거면 사용자가 자바스크립트로든 뭐로든 다시 디코딩해서 볼 수 있다는 거고
    그러면은 사용자가 이거를 조작해서 악용할수도 있음

  • 만약 조작해서 토큰의 유효기간을 50년으로 늘려준다거나 관리자 여부 같은게 토큰에 담겨있으면 이걸 true로 바꿔서 관리자 권한으로 인가를 받아버리는것을 방지하기 위해서 1번 header 와 3번 verify signature 파트가 있는거임

  • 1번 header 부터 살펴보면 header는 디코딩을 해보면 type , 토큰의 타입 2가지 정보가 담겨져있고 여기에는 항상 JWT가 들어간다.
    type이 JWT여야 JWT인거임 [고정값임] , 다른 하나는 alg(알고리즘의 약자)이게 중요하다 alg는 3번 서명값을 만드는데 사용될 알고리즘이 지정된다 (HS256등 여러 암호화 방식중 하나를 지정할수있다)
    헤더와 페이로드 , 그리고 서버에 감춰놓은 비밀 값 셋을 이 암호화 알고리즘에 넣고 돌리면 3번 서명 값이 나옴

  • 암호화 알고리즘은 한쪽방향으로는 계산이 되도 반대쪽으로는 안되서 서버만 알고있는 그 비밀 값을 찾아낼 방법이 없다는것임.
    (토큰들 잔뜩 탈취해서 백날 들여다봐도 그리고 글자 하나만 바뀌어도 3번 값이 완전히 달라지는거라 2번페이로드를 수정해서 유효한 3번 서명값이 나오려면 서버에 숨긴 비밀키를 알고 있어야하기 떄문에 이걸 조작을 못하는거임)

  • 즉 서버는 요청에 토큰값이 실려들어오면 1,2번의 값을 서버의 비밀 키 와 함께 돌려봐서 계산된 결과값이 3번 서명 값과 일치하는 결과가 나오는지 확인함 만약 2번 페이로드의 정보가 서버가 아닌 누군가에 의해 조금이라도 수정되었다면 당연히 안 맞는다.
    (정보를 조작한 사용자이거나 해커로 간주되어 거부됨)
    3번서명값과 계산값이 일치하고 , 유효기간도 지나지 않았다면 그 사용자는 로그인 된 회원으로서 인가를 받는것
    (그럼 이제 서버는 사용자들의 성태를 어디다가 따로 기억을 해둘 필요가없이 , 이비밀값만 손에 쥐고 있으면 요청들 들어올때마다 토큰 확인해서 사용자들을 걸러낼수있음)

  • 이처럼 시간에 따라 바뀌는 어떤 상태값을 안 갖는 걸 stateless하다고 한다. 세션은 반대로 stateful임

세션을 대체하기에는 아쉬운 JWT의 결점

  • 세션처럼 stateful해서 , 모든 사용자들의 상태를 기억하고 있다는 건 구현하기 부담되고 고려사항도 많지만 , 이게 되기만하면 기억하는 대상의 상태들을 언제든 제어할 수 있다는 의미임
  • 예를 들어서 한기기에서만 로그인 가능한 서비스를 만들려는 경우 PC에서 로그인한 상태의 어떤 사용자가 핸드폰에서 또 로그인하면 PC에서는 로그아웃되도록 기존 세션을 종료할 수 있는거임
  • 즉 세션방식에서는 메모리(책상)에 올려둔 기존 표를 버리면되는데 JWT는 이런게 불가능함
    이미 줘버린 토큰을 뺏을수도없고 그 토큰의 발급내역이나 정보를 서버가 어디 기록해서 추적하고 있는것도 아니기때문에
    내가 쥐고 있을 필요가 없어서 편하기는 한데 , 그래서 통제는 못한다.
    그렇다고 어디 상태를 기억해둘려고 한다면 세션이랑 똑같아져버려서 의미가 없어짐
  • 더 심각한 경우 어떤 토큰이 해커에게 탈취당한경우 해커가 가져가버린 토큰을 무효활 방법이 없음 그래서 실서비스중에 JWT만으로 인가를 구현하는 곳은 잘없음

결점 보완방법

  • 만료시간을 가깝게 잡아서 토큰의 수명을 아주 짧게 주는것임
    (이러면 몆분 있다가 또 로그인해야하는 번거로움이 생김)
  • 그래서 로그인을 하고 나면 토큰을 2개를 줌
    (수명이 몆시간이나 몆분이하로 짧은 access토큰이랑 꽤 길게 ,보통 2주 정도로 잡혀 있는 refresh토큰)

access , refresh 토큰 둘을 구현하는 여러방법들 중하나

  • access , refresh을 발급하고 클라이언트에게 보내고 나서 리프레쉬 토큰은 , 상응값을 데이터베이스에도 저장함
    손님은 엑세스 토큰의 수명이 다하면 리프레쉬 토큰을 보냄
  • 서버는 그걸 데이터베이스에 저장된 값과 대조해보고 맞다면 새 엑세스 토큰을 발급해줌
  • 이제 이 리프레쉬 토큰만 안전하게 관리된다면 이게 유효할동안은 엑세스 토큰이 만료될때마다 다시 로그인을 할 필요 없이 새로발급을 받을수 있음
  • 즉 매번 인가를 받을 때 쓰는 짧은 수명 토큰이 엑세스 토큰이고 엑세스 토큰을 재발급받을 때 쓰는게 리프레쉬 토큰이다.
    그렇게 하면 중간에 엑세스 토큰이 탈취당해도 오래 쓰지 못함
    누구를 강제 로그아웃시킬려면 리프레쉬 토큰을 갖다가 DB에서 지워버려서 토큰갱신이 안되게 하면 됨
  • 하지만은 그렇게 해도 짧게나마 엑세스 토큰이 살아있는 동안은 이걸 바로 차단할 방법은 없다
  • 그냥 토큰하나로만 쓰는것보다는 훨씬 낫지만은 이것도 아주 속 시원하게 빈틈없는 해결책은 아니다.
  • 아무리 JWT가 구현하기 편리하고 좋더라도 이런점이 JWT의 한계이기 떄문에 내 서비스가 JWT를 사용하기에 적합한지 충분히 고려해야함
    위의 문제들이 큰 이슈가 안되는 종류의 서비스에서는 정말 편리하고 경제적인 인가 방식이 됨

API(Application Programming Interface)

Interface

  • 상호간의 소통을 위해 만들어진 접점 (키보드 ,리모컨 등등)

User Interface

  • 사용자가 사용하는 인터페이스 (홈페이지 화면등등)

API란

  • 응용 프로그램에서 사용할 수있도록 , 운영체제나 프로그래밍 언어가 제공하는 기능을 제어할 수 있게 만든 인터페이스

  • 소프트웨어가 다른소프트웨어로부터 지정된 형식으로 요청 . 명령을 받을 수 있는 수단 (프로그램이 서로 소통하는 방법)
    (코드들끼리 서로 소통하기위해 만들어진것)

  • 서버에 정보를 달라고 하는것을 요청=request라고 하고 찾은정보를 내 사이트에 받는것은 응답=response라고 한다.
    -네트워크에서 기기들간의 의사소통 해나가는 규격사항을 HTTP라고 부른다

  • 라이브러리나 프레임워크에서 우리가이용할수있는 클래스나 함수들도 API라고 부름

  • 내부의 구현사항을 잘숨겨두고 외부에서 사용하는 사람이 필요한것만 노출해 두고 이것을 인터페이스, API라고 부른다

API가 가져야할 내용

    1. 요청방식이 들어가야함 (GET ,POST)
    1. 어떤 데이터를 요청할것인지
    1. 자료요청에 필요한 추가정보

API의 종류들

API는 데이터서버를 갖고있는 사람들이 원하는대로 디자인 할수있음

  • WebAPI = 브라우저를 위해 만든 API를 뜻함
  • OpenAPI = 회사 내부에서 사용하는 WebAPI를 외부의 다른 개발자가 이용할 수 있도록 공개적으로 오픈한것 (누군가 서버를 만들어놓고 여기에 주소와 사용규칙을 공개한것을 의미한다)
  • privateAPI =사내에서는 쓰는 API

카카오 책검색 Open API 로 예를 들어봄

 1 요청 (request)
	1. 주소 : "https://naver.com"
    2.전송방식 : GET
    3.보낼것 : 
			query 검색어 (필수)
			sort  정렬방식 (선택)
            target 검색대상 (선택)

2. 응답 (response)
	1. 형식:JSON
	2. 응답 의미 설명 
			title	  도서제목
            contents  도서소개
            thumbnail 도서표지 썸네일  URL 
  • 정보 전송 방식은 크게 GET과 POST로 나눌수 있는데
  • 겟 방식은 주소창에 모든 정보를 담아 정보를 전달하는 방식
  • 포스트방식은 주소창이 아니라 내부적으로 정보를 전송하는 방식이다
  • 보낼것은 API요청에서 필요한 정보들을 의미함>

0개의 댓글