다른 팀원이 만든 코드와 내가 구현한 로그인/로그아웃/회원가입 기능을 병합해보았다.별거 아닌 오류때문에 몇 시간 낭비는 했지만 팀장님 덕분에 마지막엔 내 컴퓨터에서도잘 돌아가는 것을 확인했다.
상세 페이지 합치는 일만 남았는데 상세 페이지를 맡은 팀원님이 밤까지 새며 너무 열심히 해주셔서 팀장님이 오늘 마무리하시고 내일 쯤엔 올릴 수 있을 것 같다.
거의 클론코딩 수준으로 강의를 보며 로그인/로그아웃/회원가입 기능을 구현하였기 때문에
시간이 조금 남아서 Figma 와이어프레임을 짜보고 내가 짠 코드들을 공부해보며 로그인 구현 방식 중 JWT 세션/쿠키 방식을 공부해보았다.
<Figma 와이어프레임>
내가 정리해본 로그인 JWT방식과 세션/쿠키방식
-로그인/회원가입/로그아웃 구현-
★해시함수 - 임의의 데이터를 입력받아 항상 고정된 길이의 임의 값으로 변환해주는 함수
<ex)18138372fad4b94533cd4881f03dc6c69296dd897234e0cee83f727e2e6b1f63>
id_receive = request.form['id_give']
pw_receive = request.form['pw_give']
nickname_receive = request.form['nickname_give']
// request.form을 통해서 id,pw,nicknam를 받아옴
pw_hash = hashlib.sha256(pw_receive.encode('utf-8')).hexdigest()
// pw 해시함수를 DB에 저장한다는 것
db.user.insert_one({'id': id_receive, 'pw': pw_hash, 'nick': nickname_receive})
// db에 insert를 해줌 그전에 pw_hash로 암호화하여 db에 저장
★JWT란?
JSON Web Token의 줄임말 JSON 객체를 사용해 정보를 안전하게 전달하는 웹표준
(회원가입 후 로그인 시 서버에 회원인증 토큰을 생성하여 넘겨줌 토큰 유무를 확인하여
회원만 접근 가능한 영역을 사용이 가능케함)
①Session / Cookie 방식
-세션 쿠키 방식은 기본적으로 세션 저장소를 필요로함(Redis를 많이사용)
-세션 저장소는 로그인을 했을 때 사용자의 정보를 저장하고 열쇠가 되는 세션 ID값을 만듬
그리고 HTTP 헤더에 실어 사용자에게 돌려보냄
-사용자는 쿠키로 보관하고 있다가 인증이 필요한 요청에 쿠키(세션ID)를 넣어 보냄
'세션' = 서버에서 가지고 있는 정보
'쿠키' = 사용자에게 발급된 세션을 열기 위한 열쇠(SESSION ID)를 의미
쿠키만으로 인증을 사용한다는 것은 서버의 자원은 사용하지 않는 것!
이렇게 쿠키만으로 인증을 사용할 경우에는 클라이언트가 인증정보를 책임지게됨!
결국 HTTP 요청을 탈취당할 경우 정보가 다 털리게됨 그러므로 보안과는 상관없는
장바구니 자동로그인 설정 같은 경우에 쓰임!
결론 .. 인증의 책임을 서버가 지게하기 위해 세션을 사용하는 것임(사용자가 해킹당하는 것 보다
서버를 해킹당하는 것이 훨씬 어렵기때문에) 사용자(클라이언트)는 쿠키를 이용하고, 서버에서는
쿠키를 받아 세션의 정보를 접근하는 방식으로 인증함.
장점 - * 이 방식은 기본적으로 쿠키를 매개로 인증을 거침. 쿠키가 담긴 HTTP요청이 도중에 노출되어도
쿠키 자체(세션ID)는 유의미한 값을 가지고 있지 않다(중요한 정보는 서버 세션에 담겨있음)
* 사용자A는 1번, 사용자B는 2번 이럭식으로 고유의 ID값을 발급받게 되는데, 그렇게 되면 서버에서는 쿠키값을 받았을 때
일이 회원정보를 확인할 필요 없이 바로 어떤회원인지를 확인할 수 있어 서버의 자원에 접근하기 용이함
단점 - * 쿠키가 담긴 HTTP요청 도중 노출되어도 쿠키자체는 유의미한 값을 가지고있지 않아 안전하다하였는데,
만약 A 사용자의 HTTP 요청을 B사용자(해커)가 가로챘다면 그 안에 들어있는 쿠키도 충분히 훔칠 수 있다.
B사용자가 가로챈 쿠키를 이용해 HTTP에 요청을 보내면 서버의 세션저장소에서는 A사용자로 오인해
정보를 잘못 뿌려줄 수도 있다(이것을 세션 하이재킹 공격이라고 함)
->해결책 : HTTPS를 사용해 요청 자체를 탈취해도 안의 정보를 읽기 힘들게한다.
세션에 유효시간을 넣어준다.
★HTTP와 HTTPS의 차이점
프로토콜-> 정보기기 사이에서 통신을 통한 정보교환이 필요할 경우 이러한 통신을 원활하게 하기 위해 사전에 정의한 여러
통신 규칙과 방법에 대한 약속인 통신 규약을 의미한다.
*HTTP(Hyper Text Transfer Protocol) 서버/클라이언트 모델을 따라 데이터를 주고 받기 위한 프로토콜이다.
HTTP는 하이퍼텍스트를 교환하기 위한 통신규약, 80번 포트를 사용함.
HTTP서버가 80번 포트에서 요청을 기다리고,클라이언트는 80번포트로
요청을 보내게 된다.
-HTTP는 암호화가 되지 않은 평문 데이터를 전송하는 프로토콜이였기 때문에, HTTP로 비밀번호나 주민등록번호 등 개인정보를
주고받으면 제 3자가 정보를 조회할 수 있었다. 이 문제 해결을 위해 HTTPS가 등장함!
*HTTP(Hyper Text Transfer Protocol Secure)
-HTTP는 암호화가 추가되지 않았기에 보안에 취약한 반면, HTTPS는 안전하게 데이터를 주고받을 수 있다.
HTTPS를 이용하면 암호화/복호화의 과정이 필요하기 떄문에 HTTP보다 속도가느림(요즘은 거의 차이가 없다한다..)
HTTPS는 인증서를 발급하고 유지하기위하여 추가 비용이 발생함.
개인정보,민감한데이터->HTTPS
단순한 정보 조회->HTTP
② 토큰 기반 인증 방식(JWT)
-JWT는 세션/쿠키와 함께 모바일과 웹의 인증
-인증에 필요한 정보들을 암호화시킨 토큰을 뜻함!
-세션/쿠키방식과 유사하게 사용자는 Access Token(JWT토큰)을 HTTP 헤더에 셀어 서버로 보냄
*토큰을 만들기 위한 3가지
-Header : 3가지 정보를 암호화할 방식(alg), 타입(type)등이 들어감
-Payload : 서버에서 보낼 데이터가 들어감(유저의 고유ID값,유효기간)
-Verify Signature : Base64 방식으로 인코딩한 Header,payload 그리고 SECRET KEY를 더한 후 서명됨
결과 : Encoded Header + "." + Encoded Payload + "." + Verify Signature
Header, Payload는 인코딩될 뿐 따로 암호화되지 않음 그래서 JWT 토큰에서 Header, Payload는 누구나
디코딩하여 확인 가능 누구나 디코딩이 가능하기에 Payload에는 유저의 중요한 정보(비밀번호 등)가 들어가면 쉽게 노출
될 수 있다....
하지만!!!!
Verify Signature은 SECRET KEY를 알지 못하면 복호화할 수 없다
[예를들어 A,B사용자가 있고 A가 토큰을 조작하여 B의 데이터를 훔쳐보려한다는 가정을 해보자!
그래서 Payload에 있는 A의 ID를 B의 ID로 바꿔서 다시 인코딩하고 토큰을 서버로 보냈다.
서버는 처음에 암호화된 Verify Signature를 검사하게되는데 Payload는 B사용자의 정보가
들어있으나 Verify Signature은 A의 Payload를 기반으로 암호화되었기 때문에 유효하지
않은 토큰으로 간주함 A사용자는 SECRET KEY를 알지 못하는 이상 토큰을 조작할 수 없다는
것을 확인할 수 있음!]
★JWT 인증사용 방법
장점
간편함!
JWT 발급한 후 검증만 하면 되기 때문에 세션/쿠키 방식처럼 저장소가 필요없음
서버를 확장하고 유지보수하는데 유리함
단점
이미 발급된 JWT는 돌이킬 수 없다..
세션/쿠키의 경우 쿠키가 악의적으로 사용되면 해당 세션을 지우면 그만이지만
JWT는 유효기간이 만료될 때 까지 계속 악용될 수 있음..
Payload는 정보가 제한적이다. Payload는 암호화 되지 않으므로 디코딩하면
누구나 정보를 확인할 수 있다.(세션/쿠키 방식은 유저의 정보가 모드 서버의 저장소로 안전하게 보관됨.)
Payload에는 중요한 정보를 넣을 수 없다..
JWT는 세션/쿠키 방식에 비해 길이가 길다..
이 말은 인증이 필요한 요청이 많아질수록 서버의 자원낭비 또한 많아진다는 것이다.
해결책-> Access Token의 유효기간을 짧게하고 Refresh Token이라는 새로운 토큰을 발급한다.
Access Token을 탈취당해도 상대적으로 피해를 줄일 수 있따...
<blueprint방법>
똑같은 함수이름 등으로 충돌할 가능성이 있기때문에 다음과 같은 방법으로 방지할 수 있다!
1. 해당하는 메소드를 분리한다. 분리할 때에는 페이지 단위로 해준다.
2. 분리한 페이지 내부에서 필요한 패키지들을 임포트 해준다.
3. 이때 from flask import Blueprint를 꼭 포함한다!
4. 그 후 ‘페이지이름 = Blueprint(‘페이지이름’, name)’ 으로 메소드 상단에 등록한다.
5. app.py에 돌아와서 blueprint트를 등록하는데,
6. app.register_blueprint(‘페이지이름’) 으로 해준다!
라우팅을 기본적으로 가지고있음
api는 페이지의 기능을하는 메소드는 아님
오늘처럼 코드를보면서 이해하려고 노력해야겠다. 성격상 이해하지못하고 넘어가면 너무너무 불안하다 ㅠㅠ