Chapter1. 웹 인증/보안
Chapter1-1. HTTPS
Chapter1-2. Hashing
Chapter2. Cookie / Session
Chapter2-1. Cookie
Chapter2-2. Session
과제1 - Auth Basic
Chapter3. 웹 공격의 종류
Chapter4. Token / OAuth
Chapter4-1. Token
Chapter4-2. OAuth
과제2 - Auth Token
과제3 - Auth OAuth 2.0
HTTP = 인터넷에서 데이터를 주고 받을 수 있는 통신 프로토콜
HTTP + Secure = 프로토콜 내용을 암호화
Hyper Text Transfer Protocol Secure Socket layer의 약자로 HTTP over SSL(TLS)
, HTTP over Secure
라고 부르기도 함
SSL
혹은 TLS
라는 알고리즘을 이용해, HTTP 통신을 하는 과정에서 데이터를 암호화하여 전송하는 방법임HTTPS는 다음을 목적으로 사용
전혀 다른 키 한 쌍으로 암호화 및 복호화를 진행한다.
HTTPS 프로토콜을 이용하는 서버는 한 쌍의 키 중에서 키 하나는 비밀키로, 다른 키 하나는 클라에게 공개를 해서 데이터를 안전하게 전송하도록 함
다만, 모든 통신에 대해서 공개키방식을 사용하는 것은 아님
공개키 방식은 많은 클라를 대상으로 매번 사용하기에는 연산이 복잡한 알고리즘이기에, 통신의 초창기에서만 비밀키를 만들어내기 위한 목적으로 사용한다.
1. HandShake
2. 비밀 키 생성
3. 상호 키 검증
제 3자가 서버와 클라이언트가 주고받는 정보를 탈취할 수 없도록 하는 것
HTTPS에서는 클라이언트와 서버가 데이터를 암호화하여 주고받기 위해 비대칭키 방식과 대칭키 방식을 혼용하여 사용함
💡 정리: HTTPS는 대칭키와 비대칭키 방식을 이용해 데이터를 암호화한다!
대칭키와 비대칭키를 이용한 철수와 영희의 편지 주고받기
대칭키와 비대칭키
브라우저는 서버가 전송한 '응답 + 전달받은 인증서'를 확인할 수 있다.
클라는 인증서에 작성된 도메인과 응답객체에 작성된 도메인을 비교한다. 응답에서 확인한 도메인과, 인증서에 작성된 도메인이 같지 않은 경우, 클라이언트는 서버 제공자가 아닌 전혀 다른 데이터 제공자임을 알 수 있음! 아래 그림이 제 3자 공격이 발생한 경우임
정리하면,
인증서는 서버의 신원을 보증하여 우리가 접속한 Naver가 해커가 정교하게 따라한 가짜 Naver가 아님을 보장해주는 역할을 함
CA는 인증서를 발급해주는 엄격하게 공인된 기관
코드스테이츠 웹사이트의 인증서를 살펴보면, 인증서를 발급한 CA, 서명에 사용한 알고리즘, 서명, 코드스테이츠의 공개 키 정보등이 들어있는 것을 확인할 수있음
💡 일단 이것만 이해: “인증서가 CA의 비밀키로 암호화되어 있기 때문에 CA의 개인키로 복호화 가능하다. 따라서 해당 CA에서 발급한 인증서라는 것을 보증할 수 있다.”
서버가 클라이언트에게 CA에서 발급받은 인증서를 전달하면 클라이언트는 OS 또는 브라우저에 미리 내장되어 있던 CA 리스트를 통해 브라우저에서 인증된 CA에서 발급받은 인증서인지 먼저 확인함
만약 인증된 CA에서 발급한 인증서가 아니라면 아래와 같이 화면에 경고창을 띄워 서버와 연결이 안전하지 않다는 화면을 보여줌
그 후 인증서가 확인되었다면 브라우저에 제공된 해당 CA 기관의 공개키로 서버 인증서를 복호화함
따라서 브라우저는 인증서의 도메인과 데이터를 제공하는 서버의 도메인을 비교할 수 있기 때문에 '중간자 공격'을 감지하여 보안 위협으로부터 사용자 및 사용자의 데이터를 보호할 수 있음
또한 위와 같은 경고를 직접 보여줌으로써 브라우저들은 인증된 CA가 발급한 인증서를 이용하여 데이터를 제공하는 안전한 서버를 사용자가 사용하도록 유도함
이처럼 서버와 클라이언트간의 CA를 통해 서버를 인증하는 과정과 데이터를 암호화하는 과정을 아우른 프로토콜을 TLS 또는 SSL이라고 말함. (*SSL과 TLS는 사실상 동일한 규약을 뜻하며 SSL이 표준화되며 바뀐 이름이 TLS.)
Wikipedia - 중간자 공격 (Man In The Middle Attack)
https://en.wikipedia.org/wiki/Man-in-the-middle_attack
mkcert라는 프로그램을 이용해서 로컬 환경(내 컴퓨터)에서 신뢰할 수 있는 인증서를 만들 수 있다.
macOS 사용자의 경우, Homebrew를 통해 mkcert를 설치할 수 있다.
$ brew install mkcert
먼저 다음 명령어를 통해 로컬을 인증된 발급기관으로 추가해야한다.
$ mkcert -install
다음은 로컬 환경에 대한 인증서를 만들어야 한다. localhost로 대표되는 로컬 환경에 대한 인증서를 만들려면 다음 명령어를 입력해야 한다.
$ mkcert -key-file key.pem -cert-file cert.pem localhost 127.0.0.1 ::1
이제 옵션으로 추가한 localhost
, 127.0.0.1
(IPv4), ::1
(IPv6)에서 사용할 수 있는 인증서가 완성되었다. cert.pem
, key.pem
이라는 파일이 생성된 것을 확인할 수 있다.
인증서는 공개키, 그리고 인증기관의 서명을 포함하고 있으므로 공개되어도 상관이 없지만, key.pem의 경우 개인 키이므로 git에 커밋하지 않고, 암호처럼 다루어야 한다.
Node.js 환경에서 HTTPS 서버를 작성하기 위해서는 https
내장 모듈을 이용할 수 있다. express.js를 이용해 https 서버를 만들 수도 있다.
먼저는 방금 생성한 인증서 파일들을 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 를 사용하는 경우, 다음과 같이 https.createServer의 두 번째 파라미터에 들어갈 callback 함수를 Express 미들웨어로 교체하면 됨!
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);
암호화는 일련의 정보를 임의의 방식을 사용하여 다른 형태로 변환하여 해당 방식에 대한 정보를 소유한 사람을 제외하고 이해할 수 없도록 '알고리즘'을 이용해 정보를 관리하는 과정
어떠한 문자열에 '임의의 연산'을 적용하여 다른 문자열로 변환하는 것
해시 알고리즘 철칙
1. 모든 값에 대해 해시 값을 계산하는데 오래걸리지 않아야 한다.
2. 최대한 해시 값을 피해야 하며, 모든 값은 고유한 해시 값을 가진다.
3. 아주 작은 단위의 변경이라도 완전히 다른 해시 값을 가져야 한다.
외부 알고리즘을 이용해서 해싱을 진행하면, 해시된 값('0g7s80a...')으로 DB에 저장이 됨.
-> 데이터 베이스가 털려도, 해시된 값(비밀번호)이 노출이 되어 해커가 이 비밀번호를 다른 사이트에 적용하더라도 안 뚫림
암호화해야하는 값에 어떤 '별도의 값'을 추가해 결과를 변형하는 것
서버에서 salt를 공용으로 사용하는 것이 아니라 유저마다 salt를 다르게 했을 시, 데이터 베이스에서도 salt를 각자 다르게 가지고 있어야 함
서버는 password를 넘겨 받고 암호화를 진행하는데, DB에서 넘겨받은 salt값을 가지고 해싱을 해서 비교를 하게 된다. 알고리즘이 노출돼도 보다 안전하다.
퀴즈
1. 클라이언트가 서버에게 암호화된 사용자의 비밀번호를 보내면 서버가 이를 평문으로 복호화하여 데이터베이스에 저장한다.(x)
2.Salt는 암호화해야 하는 값에 ( 별도의 값 )을 추가하여 결과를 변형하는 것을 뜻합니다.
쿠키의 개념과 작동원리 및 이를 이용한 세션 인증 방식에 대해 학습한다.
무상태성을 가진 HTTP에서 사용자의 상태를 브라우저에 저장할 수 있는 쿠키를 학습한다
사용자의 정보를 서버에 저장하고 쿠키를 이용하여 이를 검증하는 세션 인증 방식에 대해 학습한다.
서버는 쿠키를 이용하여 데이터를 클라이언트에 저장하고 이 데이터를 다시 불러와 사용할 수 있음
'Set-Cookie':[
'cookie=yummy',
'Secure=Secure; Secure',
'HttpOnly=HttpOnly; HttpOnly',
'Path=Path; Path=/cookie',
'Doamin=Domain; Domain=codestates.com'
]
특정 조건들은 위 코드처럼 쿠키 옵션으로 표현할 수 있음
도메인은 흔히 사용하는 www.google.com
과 같은 서버에 접속할 수 있는 이름.
쿠키 옵션에서 도메인은 포트 및 서브 도메인 정보, 세부 경로를 포함하지 않음.
여기서 서브 도메인이란 www 같은 도메인 앞에 추가로 작성되는 부분을 말함
따라서 요청해야 할 URL이 http://www.localhost.com:3000/users/login
이라 하면 여기에서 Domain은 localhost.com
이 됨.
만약 쿠키 옵션에서 도메인 정보가 존재한다면 클라이언트에서는 쿠키의 도메인 옵션과 서버의 도메인이 일치해야만 쿠키를 전송할 수 있다. 이를 통해 naver.com에서 받은 쿠키를 google.com에 전송하는 일을 막을 수 있음
Path는 세부 경로로써 서버가 라우팅할 때 사용하는 경로를 의미
http://www.localhost.com:3000/users/login
인 경우라면 여기에서 Path, 즉 세부 경로는 /users/login
이 됩니다. 이를 명시하지 않으면 기본적으로 /
으로 설정되어 있음
Path 옵션의 특징은 설정된 경로를 포함하는 하위 경로로 요청을 하더라도 쿠키를 서버에 전송할 수 있음
Path가 /users로 설정되어 있고, 요청하는 세부 경로가 /users/codestates 인 경우라면 쿠키 전송이 가능
하지만 /posts/codestates로 전송되는 요청은 Path 옵션(/users)을 만족하지 못하기 때문에 서버로 쿠키를 전송할 수 없음
쿠키가 유효한 기간을 정하는 옵션. 만약 쿠키가 영원히 남아있다면 그만큼 탈취되기도 쉬워지기 때문에 이러한 유효기간을 설정하는 것이 보안 측면에서 중요함
MaxAge
는 쿠키가 유효한 시간을 초 단위로 설정하는 옵션
Expires
은 언제까지 쿠키가 유효한지 심판의 날을 지정할 수 있음. 이때 옵션의 값은 클라이언트의 시간을 기준으로 함. 이후 지정된 시간, 날짜를 초과하게 되면 쿠키는 자동으로 파괴됨
쿠키는 위 옵션의 여부에 따라 세션 쿠키(Session Cookie)와 영속성 쿠키(Persistent Cookie)로 나뉨
세션 쿠키: MaxAge 또는 Expires 옵션이 없는 쿠키로, 브라우저가 실행 중일 때 사용할 수 있는 임시 쿠키입니다. 브라우저를 종료하면 해당 쿠키는 삭제됨
영속성 쿠키: 브라우저의 종료 여부와 상관없이 MaxAge 또는 Expires에 지정된 유효시간만큼 사용가능한 쿠키
사용하는 프로토콜에 따른 쿠키의 전송 여부를 결정하는 옵션. 만약 Secure 옵션이 true로 설정된 경우 HTTPS를 이용하는 경우에만 쿠키를 전송할 수 있음
즉, Secure 옵션이 없다면 프로토콜에 상관없이 http://www.codestates.com
또는 https://www.codestates.com
에 모두 쿠키를 전송할 수 있음
자바스크립트에서 브라우저의 쿠키에 접근 여부를 결정. 만약 해당 옵션이 true로 설정된 경우, 자바스크립트로 쿠키에 접근이 불가함
명시되지 않는 경우 기본으로 false
로 지정되어 있습니다. 만약 이 옵션이 false인 경우 document.cookie
를 이용해 자바스크립트에서 쿠키접근이 가능하므로 XSS 공격에 취약함
Cross-Origin 요청을 받은 경우, 요청에서 사용한 메소드와 해당 옵션의 조합을 기준으로 서버의 쿠키 전송 여부를 결정하게 됨. 사용 가능한 옵션은 다음과 같음
Lax
: Cross-Origin 요청이라면GET
메소드에 대해서만 쿠키를 전송할 수 있다.GET
요청이라면 쿠키 전송이 가능하다.Strict
: 단어 그대로 가장 엄격한 옵션으로, Cross-Origin이 아닌 same-site 인 경우에만 쿠키를 전송 할 수 있음None
: Cross-Origin에 대해 가장 관대한 옵션으로 항상 쿠키를 보내줄 수 있음 다만 쿠키 옵션 중 Secure 옵션이 필요.💡 이때 same-site는 요청을 보낸 Origin과 서버의 도메인, 프로토콜, 포트가 같은 경우를 말함. 이 중 하나라도 다르다면 Cross-Origin으로 구분됨
서버에서 이러한 옵션들을 지정한 다음, 서버에서 클라이언트로 쿠키를 처음 전송하게 된다면 헤더에 Set-Cookie
라는 프로퍼티로 쿠키를 담아 전송함.
이후 클라이언트에서 서버에게 쿠키를 전송해야 한다면 클라이언트는 헤더에 Cookie
라는 프로퍼티에 쿠키를 담아 서버에 쿠키를 전송
쿠키의 특성을 이용하여 서버는 클라이언트에 인증정보를 담은 쿠키를 전송하고, 클라이언트는 전달받은 쿠키를 서버에 요청과 같이 전송하여 Stateless
한 인터넷 연결을 Stateful
하게 유지할 수 있음
하지만 기본적으로 쿠키는 오랜 시간 동안 유지될 수 있고, HttpOnly 옵션을 사용하지 않았다면 자바스크립트를 이용해서 쿠키에 접근할 수 있기 때문에 쿠키에 민감한 정보를 담는 것은 위험하다!
이런 인증정보를 이용해 공격자가 유저인척 서버에 요청을 보낸다면 서버는 누가 요청을 보낸 건지 의심하지 않고 이를 인증된 유저의 요청으로 취급하게 됨. 이때 개인정보와 같은 민감한 정보를 공격자가 탈취한다면 2차 피해가 일어날 수 있음.
참고 MDN - Set-Cookie Attributes
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
사용자가 웹사이트에서 아이디 및 비밀번호를 이용해서 로그인을 시도하면(그림에서 1번), 과연 어떤 일이 벌어질까?
💡 인증에 따라 리소스의 접근 권한(Authorization)이 달라짐
이때 서버와 클라이언트에 각각 필요한 것은 다음과 같음
쿠키를 통해 유효한 세션 아이디가 서버에 전달되고, (5번) 세션 스토어에 해당 세션이 존재한다면 (6번) 서버는 해당 요청에 접근 가능하다고 판단함. (7,8번)
쿠키에 세션 아이디 정보가 없는 경우, 서버는 해당 요청이 인증되지 않았음을 알려줌
세션 아이디가 담긴 쿠키는 클라이언트에 저장되어 있으며, 서버는 세션을 저장하고 있음. 그리고 서버는 그저 세션 아이디로만 인증 여부를 판단함
💡 주의: 앞에서도 말했지만, 쿠키는 세션 아이디, 즉 인증 성공에 대한 증명을 갖고 있으므로, 탈취될 경우 서버는 해당 요청이 인증된 사용자의 요청이라고 판단함. 이것이, 우리가 공공 PC에서 로그아웃해야 하는 이유
그러므로 로그아웃은 다음 두 가지 작업을 해야 함
서버는 클라이언트의 쿠키를 임의로 삭제할 수 없음. 대신, set-cookie
로 클라이언트에게 쿠키를 전송할 때 세션 아이디의 키값을 무효한 값으로 갱신할 수 있음
Node.js에는 이런 세션을 대신 관리해 주는 express-session 이라는 모듈이 존재함
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 옵션의 비밀키를 이용해 암호화해 세션 id라는 것을 생성하고, 이것을 클라이언트에게 쿠키로 전송함
쿠키로 전송된 세션 id는 이에 종속되는 고유한 세션 객체를 가지며 이는 서버에 저장됨. 이때 세션 객체는 유저별로 독립적으로 생성된 객체이므로 유저별로 각각 다른 데이터를 저장할 수 있음
따라서 클라이언트에 유저의 개인정보를 담지않고도 서버가 클라이언트의 세션 id를 이용해 유저의 인증여부를 판단할 수 있음
세션 객체는 req.session으로 접근할 수 있으며 앞서 말했듯 이를 통해 세션에 임의의 데이터를 저장하거나 불러올 수 있음..
-> setAttribute, getAttribute 메서드
💡즉, 서버는 사용자가 인증에 성공하면 로그인 상태를 유지하기 위해 해당 사용자의 정보를 담은 세션 객체를 생성함. 그리고 이에 접근할 수 있는 id를 암호화하여 쿠키로서 사용자에게 전달함
이 세션 객체에 값을 담거나, 값을 불러오는 법, 세션을 파괴하는 법은 다음 문서를 참고
https://github.com/expressjs/session#reqsession
The Open Web Application Security Project의 약자로서, 전세계의 보안 전문가들이 웹의 보안에 대한 표준을 정의하고 이에 대해 기업과 개발자들에게 효율적인 정보를 제공하는 오픈소스 커뮤니티
OWASP는 주로 웹에 관한 정보노출, 악성 파일 및 스크립트, 보안 취약점 등을 주제로 연구하며, 3년 정도의 주기를 두고 웹의 10대 취약점들에 대한 OWASP TOP 10을 발표하고 있음
이번 챕터에서는 2017년과 2021년에 발표한 OWASP TOP 10을 기반으로 프론트엔드 개발자가 알아두면 좋을 웹 공격들에 대해 살펴봄
SQL: Structured Query Language (구조적 질의 언어)의 줄임말로, 관계형 데이터베이스 시스템(RDBMS)에서 데이터를 관리 및 처리하기 위해 설계된 선언형 프로그래밍 언어
데이터베이스에서 임의의 SQL문을 실행할 수 있도록 명령어를 삽입하는 공격 유형
’OR ‘1’ = ‘1
을 넣어 보낸다면, WHERE절에서 OR는 AND보다 연산 순위가 낮기 때문에 OR
절인 ‘1’ = ‘1’
(항상 참)이 가장 나중에 실행되어 결국 로그인에 성공함'; DROP TABLES users;--'
)을 작성한다면 데이터가 모두 삭제되는 큰 피해를 입을 수도 있음XSS(Cross-Site Scripting, 사이트 간 스크립팅)는 웹 사이트 관리자가 아닌 이(공격자)가 웹 사이트에 악의적인 스크립트를 심어놓는 행위를 말함. 주로 클릭을 유도하는 글을 작성한 후, 해당 글을 클릭하면 공격자가 심어놓은 스크립트가 실행되어 웹 사이트 이용자에게 피해를 줌
이 공격의 대상은 클라이언트로, 사용자가 의도하지 않은 행동을 하게하거나 사용자의 쿠키 등 민감한 정보를 탈취함. XSS로 탈취한 사용자의 민감한 정보를 이용해 권한을 획득한 후 이를 이용해 CSRF 등 다양한 공격에 활용함
Stored XSS는 스크립트가 서버에 저장되어 여러 사용자에게 피해를 줄 수 있는 유형으로, 지속적(Persistent)기법이라고도 함
Reflected XSS는 URL 파라미터를 사용해 스크립트를 만드는 유형으로, 비 지속적(Non-persistent) 기법이라고도 함
이 스크립트는 서버에 저장되지 않으며 웹 어플리케이션의 지정된 파라미터를 사용할 때 나타나는 취약점을 이용함
주로 공격이 일어나는 곳은 검색엔진으로, 검색 결과가 없는 경우 입력 결과를 HTML 문서에 포함하여 응답하는 특성을 이용하기 때문에 반사(Reflected) XSS라고 부름
CSRF 공격과 비슷한 듯 하지만 CSRF는 공격자가 사용자의 권한을 탈취하여 서버에 가짜 요청을 보내는 반면, Reflected XSS의 경우 악성 스크립트가 실행되는 곳, 즉 공격 대상이 서버가 아닌 클라이언트라는 점에서 엄연히 다르다
<>
)가 글자 그대로 저장되지 않게 방지할 수 있음 <>
)와 같은 특수문자가 있는지 검증할 수 있음<>
)를 HTML 문자 참조로 치환 후 저장.쿠키에 httpOnly 설정이 되어있지 않다면 document.cookie로 자바스크립트를 통해 쿠키에 접근할 수 있음. 해당 설정을 이용해 쿠키를 브라우저에서 조회할 수 없도록 할 수 있음
세션 인증 방식을 보완한 토큰 인증 방식에 대해 학습한다.
그 중 대표적인 토큰 인증 방식인 JWT에 대해 학습하고 어떻게 JWT가 사용자의 정보를 암호화하여 토큰을 저장하는 지 이해한다.
더 나아가 직접 서버에서 인증과 관련된 로직을 처리할 필요없이 인증을 중개하는 외부 서버를 이용한 Oauth 기술에 대해서도 학습한다.
이를 통해 소셜 로그인의 작동 방식을 살펴본다.
세션 기반 인증은 서버(혹은 데이터베이스)에 유저 정보를 담는 인증 방식이었음. 서버에서는 유저가 민감하거나 제한된 정보를 요청할 때마다 "지금 요청을 보낸 유저에게 우리가 정보를 줘도 괜찮을까?
를 확인하기 위해 클라가 보낸 세션 ID를 서버 본인이 가지고 있는 세션 객체와 비교했다. 매 요청마다 매 요청마다 데이터베이스를 살펴보는 부담과 "이 부담을 클라에게 넘겨줄순 없을까?"에서 고안된 것이 토큰 기반 인증 토큰기반 인증!
토큰은 유저정보를 암호화하기 때문에 클라이언트에 담을 수 있음
대표적인 토큰기반 인증으로 Json 포맷으로 사용자에 대한 속성을 저장하는 웹 토큰
JWT는 보통 다음의 두 가지 종류의 토큰을 이용해 인증을 구현함
1. 액세스 토큰(Access Token)
2. 리프레시 토큰(Refresh Token)
액세스 토큰: 보호된 정보들(유저의 이메일, 연락처, 사진 등)에 접근할 수 있는 권한부여에 사용함.
액세스 토큰의 유효기간이 만료되면 리프레시 토큰을 사용해서 새 액세스 토큰을 발급받는다. 이때, 유저는 다시 로그인 할 필요가 없음
JWT는 .
으로 나눠진 세 부분이 존재하며 각각을 Header, Payload, Signature 라고 부른다.
1.Header
Header는 이것이 어떤 종류의 토큰인지(지금의 경우엔 JWT), 어떤 알고리즘으로 시그니처를 sign(암호화)할지가 적혀있다. JSON 형태로 정보가 담겨있다.
{
"alg":"HS256",
"typ": "JWT"
}
이 JSON 객체를 base64 방식으로 인코딩하면 header 완성됨
2.Payload
서버에서 활용할 수 있는 유저의 정보가 담겨 있다.
여기에는 어떤 정보에 접근 가능한지에 대한 권한, 또는 유저의 이름과 같은 개인정보 등을 담을 수 있음
페이로드는 시그처를 통해 유효성이 검증될 정보이긴 하나 너무 민감한 정보는 담지 않는 것이 좋다. 디코딩이 쉬운 base64방식으로 인코딩 되기 때문이다.
{
"sub": "someInfomation",
"name": "doyeon",
"iat": 151623391
}
마찬가지로, 이 JSON 객체를 base64 방식으로 인코딩하면 payloadr가 완성됨
3. Signature
base64로 인코딩된 header, payload가 완성이 되면, Signature는 이를 서버의 비밀키(암호화에 추가할 salt)와 헤더에서 지정한 알고리즘을 사용해 암호화한다.
base64 인코딩 자체는 누구나 쉽게 디코딩할 수 있어서 header와 payload 모두, 쉽게 확인 할 수 있다.
여기서 이제, 비밀키를 사용하면 이를 암호화한 값(시그니처)은 비밀키를 보유한게 아니라면 해독하는 데 엄청난 시간과 노력이 들어가게 됨
만약 HMAC SHA256 알고리즘을 사용한다면 시그니쳐는 다음과 같은 방식으로 생성된다.
HMACSHA256(base64UrlEncode(header) + '.' + base64UrlEncode(payload), secret);
누군가 권한을 속이기 위해 PAYload를 변조하여 Base64로 인코딩하더라도 원본 payload로 암호화한 시그니처값과 다르기 때문에 서버는 해당 토큰이 변조됐음을 알 수 있다.
JWT는 권한 부여
에 굉장히 유용하다. 예를 들어, 새로 다운받은 A
라는 앱이 Gmail과 연동되어 이메일을 읽어와야 한다고 생각해보자
유저는
1. Gmail 인증 서버에 로그인정보(아이디, 비번)을 제공한다.
2. 성공적으로 인증시 JWT를 발급받는다.
3. A앱은 JWT를 사용해 해당 유저의 Gmail 이메일을 읽거나 사용할 수 있다.
"아, 우리가 발급해준 토큰이 맞구만!"
라는 판단이 들면 클라의 요청을 처리하고 응답을 보내 준다. 1. Statelessness & Scalability(무상태성 & 확장성)
2. 안전하다
3. 어디서나 생성가능하다.
4. 권한부여에 용이하다.
우리가 웹이나 앱에서 흔히 볼 수 있는 소셜 로그인 인증 방식은 OAuth 2.0라는 기술 바탕으로 구현되는 것임!
전통적으로, 직접 작성한 서버에서 인증을 처리해주는 것과는 달리, OAuth는 인증을 중개해주는 메커니즘이다. 보안된 리소스에 액세스하기 위해 클라이언트에게 권한을 제공(Authorization)하는 프로세스를 단순화하는 프로토콜이다.
유저가 Facebook, Google, GitHub 같은 웹사이트 상의 보안된 자신의 리소스에 대해서, 다른 웹사이트 혹은 애플리케이션에게 해당 리소스에 대한 접근 권한을 부여하할 수 있는 개방형 프로토콜 중 한 종류이다.
즉, 이미 사용자 정보를 가지고 있는 웹서비스(Google, GitHub 등)에서 사용자의 인증을 대신해주고, 접근 권한에 대한 토큰을 발급한 후, 이를 이용해 내 서버에서 인증이 가능해짐
단, OAuth는 인증(Authentication)을 다른 서비스에 맡길 뿐, 접근권한 관리(Authorization)는 순전히 내 서버의 몫이다!
💡 OAuth 2.0은 인증을 위한 표준 프로토콜의 한 종류
(이 예시에서 페북서버가 Resouce server, Authorization server 두 가지 모두 담당)
액세스토큰을 받았다면, 이제 복잡한 과정을 거치지 않고도 아래와 같이 바로 유저의 resource에 접근 가능하다!
Resource Owner : 리소스 가진 유저~
김코딩이 구글계정을 이용해 App에 로그인할 꼉우, 이때 김코딩이 리소스오너가 된다.
Client: Resource owner를 대신하여 보호된 리소스에 액세스하는 응용프로그램(앱). 클라는 서버, 데스크탑, 모바일 또는 기타 장치에서 호스팅할 수 있다. 김코딩이 A라는 앱을 Google소셜로그인을 이용해 사용한다면 A가 클라이언트가 된다.
Resource server: client의 요청을 수락하고 응답할 수 있는 서버. 클라가 Google Photo에서 김코딩의 사진을 가져오는 경우 Google Photo가 리소스 서버가 된다. 리소스 서버는 내 앱(클라)가 보여준 액세스 토큰을 확인하고 내 앱(클라)에게 리소스를 응답해주는 서버이다.
Authorization server: Resource server가 액세스 토큰을 발급받는 서버. 리소스 오너를 성공적으로 인증한 후 클라에게 액세스 토큰을 발급하는 서버
Authorization grant: 클라가 액세스 토큰을 얻을 때 사용하는 자격 증명, 클라가 액세스 토큰을 얻는 방법. 다음과 같은 방법들이 주로 사용된다.
Authorization code: Authorization grant의 한 타입으로, 액세스 토큰을 발급받기 전에 필요한 Code.
Client ID로 이 Code를 받아온 후
, Code + Client Secret을 이용해 액세스 토큰을 받아올 수 있다.
즉, 액세스 토큰을 발급받기 위해 Client ID + Client Secret 이 필요한데, 이 두가지가 포함된 일종의 허가증이 Authorization code
Access token: 보호된 리소스에 액세스하는데 사용되는 Credentials. Authorization code와 Client Secret을 이용해 받아온 이 토큰으로 이제 리소스 서버에 접근할 수 있다.
클라에게 발급된 권한을 나타내고 문자열타입이다.
Scope: 토큰의 권한을 정의한다!. 주어진 액세스 토큰을 사용해서 액세스할 수 있는 리소스의 범위. 사진첩에는 접근할수 있어도 연락처 등 다른 리소스에는 접근할 수 없도록 접근 권한을 지정할 수 있다.
즉, 위 case study에서 각자의 역할을 나타내면
client가 액세스 토큰을 얻는 여러 방법
가장 일반적으로 쓰이는 방법으로, 액세스 토큰을 받아오기 위해서 먼저 Authorization Code를 받은 뒤, 액세스 토큰과 교환하는 방법
Authorization Code 절차를 거치는 이유? 보안성 강화 목적
client에서 client-secret을 공유하고 액세스 토큰을 가지고 오는 것은 탈취될 위험이 있기 때문에, client(내 앱)에서는 Authorization Code만 받아오고, 내 앱의 server가 access token 요청을 진행한다.
액세스 토큰을 발급받고 나면 더이상 client는 Authorization 서버를 통하지 않고, 리소스 서버와 직접적으로 소통한다!
일정 기간 유효 시간이 지나서 만료된 액세스 토큰을 편리하게 다시 받아오기 위해 사용하는 방법
https://codestates.notion.site/codestates/Auth-Basic-fcb9de4219994a2c8cdfad45a328d49d