Hyper Text Transfer Protocol Secure Socket layer
HTTPS는 HTTP 요청을 SSL 혹은 TLS라는 알고리즘을 이용해, HTTP 통신을 하는 과정에서 내용을 암호화하여 데이터를 전송하는 방법
HTTPS 프로토콜의 특징
암호화된 데이터를 주고받기 때문에, 중간에 인터넷 요청이 탈취되더라도 그 내용을 알아볼 수 없다.
브라우저가 응답과 함께 전달된 인증서 정보를 확인할 수 있다.
브라우저는 인증서에서 해당 인증서를 발급한 CA 정보를 확인하고 인증된 CA가 발급한 인증서가 아니라면 아래와 같이 화면에 경고창을 띄워 서버와 연결이 안전하지 않다는 화면을 보여줍니다.
데이터 제공자의 신원을 확인하고 보장 받는 이유는?
클라이언트는 데이터 제공자가 제공해준 데이터를 사용할 수 없어서,
서버에 데이터 요청을 하고 이후 받은 데이터를 이용해서 화면을 렌더링을 해야한다.
그렇기에 요청 및 응답을 중간에서 가로채는 중간자 공격에 취약
'중간자 공격'은 클라이언트와 서버 사이에서 공격자가 서로의 요청, 응답의 데이터를 탈취 및 변조하여 다시 전송하는 공격입니다.
데이터가 중간에 다른 도메인을 거쳐서 전달되기 때문에 서버가 해당 데이터는 https://example.com 도메인에서 제공되었습니다. 라는 추가데이터를 응답객체에 실어 보낸다면 '중간자 공격'으로 인해 다른 도메인에서 데이터를 받은 클라이언트는 데이터를 제공한 도메인과 전달받은 내용의 도메인을 비교하여 '중간자 공격'이 존재하는지 아닌지 확인할 수 있다.
mkcert라는 프로그램을 이용해서 로컬 환경(내 컴퓨터)에서 신뢰할 수 있는 인증서를 만들 수 있습니다.
설치방법
$ brew install mkcert
//If you use a firefox you add this too
$ brew install nss
로컬 호스트 환경에대한 인증서를 만들기 위해서
$ mkcert -key-file key.pem -cert-file cert.pem localhost 127.0.0.1 ::1
이로 부터 key.pem과 cert.pem을 얻게 되고 이것으로 쿠키, 세션, 토큰에 이용
인증서 파일들을 HTTPS 서버에 적용해주려면??
//node.js https 모듈 이용
const https = require('https');
const fs = require('fs');
https
.createServer(
{
key: fs.readFileSync(__dirname + '/key.pem', 'utf-8'),
cert: fs.readFileSync(__dirname + '/cert.pem', 'utf-8'),
},
function (req, res) {
res.write('Congrats! You made https server now :)');
res.end();
}
)
.listen(3001);
//express.js 이용
const https = require('https');
const fs = require('fs');
const express = require('express');
const app = express();
https
.createServer(
{
key: fs.readFileSync(__dirname + '/key.pem', 'utf-8'),
cert: fs.readFileSync(__dirname + '/cert.pem', 'utf-8'),
},
app.use('/', (req, res) => {
res.send('Congrats! You made https server now :)');
})
)
.listen(3001);
어떠한 문자열에 임의의 연산을 적용하여 다른 문자열로 변환하는 것
특징
암호화 해야하는 값에 어떤 별도의 값을 추가하여 결과를 변형 하는 것 (진짜 양념 치는거임)
왜 양념을 쳐야할까?
암호화만 해놓으면 해쉬된 결과 값이 늘 동일
-> 해쉬된 값과 원래 값의 테이블(레인보우 테이블)로 만들어서 decoding하면 쉽게 해킹당함
별도의 값을 추가했기에 기존 해쉬값과 전혀 다른 값을 가질 뿐만 아니라 알고리즘이 노출되어도 원본 값을 보호 가능
https://crackstation.net/
여기서 해쉬 값을 확인가능한데
솔트의 정보를 서버가 가지고 있고,
비밀번호에 + 양념을 쳐서 해쉬를 하게 된다.
좀 더 코드적으로 본다면
//original simple hashing
sha256('redflOwer') //hashed
//hashing with salt
sha256('8zff4gflgfd93fgdl4fgdgf4mlf45p1redflOwer')
즉, 솔트 값을 추가하면 완전히 다른 값을 가지게 된다.
https://emn178.github.io/online-tools/sha256.html
직접 예제를 encoding 해볼 수 있는 사이트
쿠키는 서버에서 클라이언트에 데이터를 저장하는 방법의 하나입니다.
기존 http의 가장 큰 문제점은 바로 statless(무상태성)이다.
인터넷 쇼핑에 있어서 장바구니의 항목들이 우리가 아무리 접속이 오래되도 다음 날 들어가도 유지되는 이유가 바로 이 쿠키 때문이다.
여기서 서브 도메인이란 www 같은 도메인 앞에 추가로 작성되는 부분을 말합니다.
따라서 요청해야 할 URL이 http://www.localhost.com:3000/users/login 이라 하면
여기에서 Domain은 localhost.com이 됩니다.
만약 쿠키 옵션에서 도메인 정보가 존재한다면 클라이언트에서는 쿠키의 도메인 옵션과 서버의 도메인이 일치해야만 쿠키를 전송할 수 있습니다.
명시하지 않으면 기본으로 / 으로 설정되어 있습니다.
Path 옵션의 특징은 설정된 path를 전부 만족하는 경우 요청하는 Path가 추가로 더 존재하더라도 쿠키를 서버에 전송할 수 있습니다.
즉 Path가 /users로 설정되어 있고, 요청하는 세부 경로가 /users/login 인 경우라면 쿠키 전송이 가능합니다.
하지만 /user/login으로 전송되는 요청은 Path 옵션을 만족하지 못하기 때문에 서버로 쿠키를 전송할 수 없습니다.
MaxAge는 앞으로 몇 초 동안 쿠키가 유효한지 설정하는 옵션입니다.
Expires 은 MaxAge와 비슷합니다. 다만 언제까지 유효한지 Date를 지정합니다.
이때 클라이언트의 시간을 기준으로 합니다.
이후 지정된 시간, 날짜를 초과하게 되면 쿠키는 자동으로 파괴됩니다.
하지만 두 옵션이 모두 지정되지 않는 경우에는 브라우저의 탭을 닫아야만 쿠키가 제거될 수 있습니다.
Secure
쿠키를 전송해야 할 때 사용하는 프로토콜에 따른 쿠키전송 여부를 결정합니다.
만약 해당 옵션이 true로 설정된 경우, 'HTTPS' 프로토콜을 이용하여 통신하는 경우에만 쿠키를 전송 할 수 있습니다.
HttpOnly
자바스크립트에서 브라우저의 쿠키에 접근 여부를 결정합니다.
만약 해당 옵션이 true로 설정된 경우, 자바스크립트에서는 쿠키에 접근이 불가합니다.
명시되지 않는 경우 기본으로 false로 지정되어 있습니다.
만약 이 옵션이 false인 경우 자바스크립트에서 쿠키에 접근이 가능하므로 'XSS' 공격에 취약합니다.
Lax :Cross-Origin 요청이면 'GET' 메소드에 대해서만 쿠키를 전송할 수 있습니다.
Strict : Cross-Origin이 아닌 same-site 인 경우에만 쿠키를 전송 할 수 있습니다.
None: 항상 쿠키를 보내줄 수 있습니다. 다만 쿠키 옵션 중 Secure 옵션이 필요합니다.
이때 'same-site'는 요청을 보낸 Origin과 서버의 도메인이 같은 경우를 말합니다.
이러한 옵션들을 지정한 다음 서버에서 클라이언트로 쿠키를 처음 전송하게 된다면 헤더에 Set-Cookie라는 프로퍼티에 쿠키를 담아 쿠키를 전송하게 됩니다.
이후 클라이언트 혹은 서버에서 쿠키를 전송해야 한다면 클라이언트는 헤더에 Cookie라는 프로퍼티에 쿠키를 담아 서버에 쿠키를 전송하게 됩니다.
mdn 쿠키내용
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
사용자가 인증에 성공한 상태는 세션이라고 부릅니다.
서버는 일종의 저장소에 세션을 저장
=> in-memory(like js 객체), 세션 스토어(redis 등과 같은 트랜잭션이 빠른 DB)에 저장
클라이언 요청에 서버가 디비에서 해당 정보를 반환 할때 세션은 쿠키에 넣어서 같이 보내는데, 쿠키가 위험하기 때문에 session은 한번 더 암호화를 거치게 된다.(Set-cookie)
이 후 같은 클라이언트가 요청해 오면 기존에 저장되있던 암호화된 session id를 통해 인증을 진행하고 서버도 session id를 확인하고 요청에 결과를 응답해준다.
note: 클라이언트 로그아웃시에 서버가 클라이언트의 쿠키를 임의로 삭제할 수는 업성서 set-cookie로 세션 아이디의 키값을 무효한 값으로 갱신해야 함.
session의 단점
항상 세션 유지 데이터를 서버 저장 공간(메모리)에 가지고 있어야해서 가용 메모리가 줄어 서버의 성능이 떨어진다.
세션은 쿠키를 대체한 것이 아니라 쿠키를 이용하기 때문에 XSS공격에 취약하다.
express-session은 세션을 위한 미들웨어로, 'Express'에서 세션을 다룰 수 있는 공간을 보다 쉽게 만들어줍니다.
https://github.com/expressjs/session#reqsession
what is difference between session and cookies??
Session은 하나의 서버에서만 접속 상태를 가지기 때문에 분산 시스템에 분리하다.
이것을 해결하기 위해 나온 것이 token
토큰을 클라이언트에 저장하는 해도 괜찮은 이유는 유저 정보를 암호화한 상태로 담겨져 있기 때문이다.
JWT 구조
//json형태로 작성
{
"alg": "HS256",
"typ": "JWT"
}
{
"sub": "someInformation",
"name": "phillip",
"iat": 151623391
}
//HMAC SHA256알고리즘 사용 예시
HMACSHA256(base64UrlEncode(header) + '.' + base64UrlEncode(payload), secret);
Note: JWT는 권한 부여에 굉장히 유용.
새로 다운받은 A라는 앱이 Gmail과 연동되어 이메일을 읽어와야 한다고 생각해 보자 유저는 Gmail 인증서버에 로그인정보(아이디, 비밀번호)를 제공하고,
성공적으로 인증시 JWT 를 발급받는다
A앱은 JWT를 사용해 해당 유저의 Gmail 이메일을 읽거나 사용할 수 있다
클라이언트는 서버에 아이디 비밀번호 담아서 POST /login 전송
서버는 DB에 아이디 비밀번호가 일치하는지 확인 후 jwt토큰을 생성(access/refresh 토큰을 모두 생성)해서 응답
클라이언트는 jwt 토큰을 저장(in local stroage or react state or cookie and etc..)
->local stroage = 브라우저에 생긴 작은 저장공간?(쿠키저장가능)
->Refreshtoken은 서버에 저장
이후 클라이언트가 GET요청으로 내정보보 보기 처럼 서버에 정보를 요구함
=>http 헤더(authorization 헤더)에 토큰을 담아서 보냄
=> bearer authentication을 이용 (참고 링크)
4-1) https://learning.postman.com/docs/sending-requests/authorization/#bearer-token
4-2) https://datatracker.ietf.org/doc/html/rfc6750
토큰을 해독 후 자신들의 서버에서 보낸 값이 맞다면 요구한 정보에 대한 응답을 보내게 됨
Statelessness & Scalability (무상태성 & 확장성)
서버는 클라이언트에 대한 정보를 저장할 필요 없다. (토큰 해독이 되는지만 판단합니다) => 클라이언트에게 이 일을 맡길려고 토큰 기반을 쓰는 것
클라이언트는 새로운 요청을 보낼때마다 토큰을 헤더에 포함시키면 됩니다
(bearer authentication을 이용)
서버를 여러개 가지고 있는 서비스라면 더더욱 빛을 발휘합니다 (같은 토큰으로 여러 서버에서 인증 가능)
=> 기존 세션 방식의 한계 점을 극복
안전하다
암호화 한 토큰을 사용하고, 암호화 키를 노출 할 필요가 없기 때문에 안전합니다.
=> 클라이언트에서 토큰을 저장해도 괜찮은 이유
어디서나 생성 가능하다
토큰을 확인하는 서버가 토큰을 만들어야 하는 법이 없습니다
토큰 생성용 서버를 만들거나, 다른 회사에서 토큰관련 작업을 맡기는 것 등 다양한 활용이 가능합니다.
권한 부여에 용이하다
토큰의 payload(내용물) 안에 어떤 정보에 접근 가능한지 정할 수 있습니다
ex) 서비스의 사진과 연락처 사용권한만 부여
=>토큰의 가장 큰 장점
세션과 토큰의 차이
고급 빌딩의 사무실과 조금 시설이 낙후된 사무실을 비교하면
전자는 입구에서 부터 시작해서 각 방을 오다닐 때마다 항상 카드 키를 소지하면서 인식을 해야한다. (토큰jwt)
후자는 입구에서 한번 인증을 성공했다면 그 뒤로 건물안에 어디든 마음껏 돌아 다닐 수 있다.(세션)
추가 내용
bcrypt is a password-hashing function designed by Niels Provos and David Mazières
https://www.npmjs.com/package/bcrypt