Cookie
1. 개념
- 서버에서 클라이언트에 데이터를 저장하는 방법 중 하나
*클라이언트에 정보를 저장하는 방법
- http의 stateless 특징을 보완해주는 도구로 작은 문자열을 저장
- 서버가 원한다면 서버는 클라이언트에서 쿠키를 이용하여 데이터를 가져올 수 있음
- 데이터 저장 이후 아무 때나 데이터를 가져올 수는 없으며, 특정 조건들이 만족하는 경우에만 다시 가져올 수 있음
*특정 조건 : 쿠키 옵션으로 표현
- 쿠키를 이용하는 것은 서버에서 클라이언트에 쿠키를 전송하는 것만을 의미하지 않고, 클라이언트에서 서버로 쿠키를 전송하는 것도 포함
- 서버는 일방적으로 브라우저에 쿠키를 줄 수 있음 : 응답의 헤더를 이용해 쿠키를 보냄
*요청할 때에는 쿠키를 자동으로 함께 보내게 됨
- 쿠키 저장시 헤더를 이용
*사용 헤더 : cookie, set-cookie
stateless
- 각각의 요청은 독립적이기 때문에 이전 요청에 대한 것을 기억하지 않음
- 로그인 정보고 기억하지 못하기 때문에 로그인 정보를 쿠키에 저장
*connect.sid=session_id (키 = 값)
2. 다른 도메인간 쿠키 전송
- 요청/응답 헤더를 적절하게 설정해주면 다른 도메인이더라도 쿠키가 전송됨
1) 클라이언트
axios.post(주소, 데이터, { withCredentials: true })
axios.get("https://localhost:4000/users/userinfo", {
withCredentials: true,
})
2) 서버
app.use(cors({
origin: true,
credentials: true
}))
origin: true
는 프론트 도메인 주소가 자동으로 Access-Control-Allow-Origin에 들어감
와일드카드인 ``와는 다름
credentials
: Access-Control-Allow-Origin을 true로 만들어주는 옵션
3. 주로 사용되는 쿠키 옵션
app.use(
session({
secret: '@KKAKKA',
resave: false,
saveUninitialized: true,
cookie: {
domain: 'localhost',
path: '/',
maxAge: 24 * 6 * 60 * 10000,
sameSite: 'None',
httpOnly: true,
secure: true,
},
})
);
1) Domain
- 도메인 : 서버에 접속할 수 있는 이름
*예시 : www.naver.com
- 쿠키 옵션에서 도메인은 포트 및 서브 도메인 정보, 세부 경로를 포함하지 않음
*예시 : naver.com
(서브 도메인 : www
와 같이 도메인 앞에 추가로 작성되는 부분)
- 쿠키 옵션에 도메인 정보가 존재한다면 클라이언트에서는 쿠키의 도메인 옵션과 서버의 도메인이 일치해야만 쿠키를 전송할 수 있음
예시
- 요청해야 하는 URL :
http://www.localhost.com:3000/users/login
- 도메인 :
localhost.com
2) Path
- 세부 경로는 서버가 라우팅할 때 사용하는 경로로, 명시하지 않으면 기본으로
/
로 설정
- 설정된 path를 전부 만족하는 경우 요청하는 Path가 추가로 더 존재하더라도 쿠키를 서버에 전송할 수 있음
예시
- 요청해야 하는 URL :
http://www.localhost.com:3000/users/login
- Path, 세부 경로 :
/users/login
- Path가 /users
로 설정되어 있고, 요청하는 세부 경로가 /users/login
인 경우 쿠키 전송이 가능
- 하지만 /users/login
으로 전송되는 요청은 Path 옵션을 만족하지 못하기 때문에 서버로 쿠키를 전송할 수 없음
3) MaxAge or Expires
- 쿠키가 유효한 기간을 정하는 옵션으로 지정된 시간, 날짜를 초과하게 되면 쿠키는 자동으로 파괴됨
- MaxAge : 앞으로 몇 초 동안 쿠키가 유효한지 설정하는 옵션
- Expires : 클라이언트의 시간을 기준으로 언제까지 유효한지 Date를 지정
- 두 옵션이 모두 지정되지 않는 경우 브라우저의 탭을 닫아야만 쿠키가 제거
4) Secure
- 쿠키를 전송해야 할 때 사용하는 프로토콜에 따른 쿠키 전송 여부를 결정
- 해당 옵션이 true로 설정된 경우, HTTPS 프로토콜을 이용하여 통신하는 경우에만 쿠키를 전송할 수 있음
5) HttpOnly
- 자바스크립트에서 브라우저의 쿠키에 접근 여부를 결정
- 해당 옵션이 true로 설정된 경우, 자바스크립트에서는 쿠키에 접근이 불가
- 명시되지 않는 경우 기본으로 false로 지정
*해당 옵션이 false인 경우 자바스크립트에서 쿠키에 접근이 가능하므로 'XSS' 공격에 취약
6) SameSite
- Cross-Origin 요청을 받은 경우 요청에서 사용한 메소드와 해당 옵션의 조합으로 서버의 쿠키 전송 여부를 결정
- 옵션 지정 후 서버에서 클라이언트로 쿠키를 처음 전송하게 된다면 헤더에 Set-Cookie라는 프로퍼티에 쿠키를 담아 전송
- 이후 클라이언트 혹은 서버에서 쿠키를 전송해야 한다면 클라이언트는 헤더에 Cookie라는 프로퍼티에 쿠키를 담아 서버에 전송
옵션
- Lax :Cross-Origin 요청이면
GET
메소드에 대해서만 쿠키를 전송할 수 있음
- Strict : Cross-Origin이 아닌 same-site인 경우에만 쿠키를 전송 할 수 있음
*same-site : 요청을 보낸 Origin과 서버의 도메인이 같은 경우를 의미
- None: 항상 쿠키를 보내줄 수 있지만, 쿠키 옵션 중 Secure 옵션이 필요
*https일때만 사용 가능 (Secure: true)
3. 쿠키를 이용한 상태 유지
- 쿠키의 특성을 이용해 서버는 클라이언트에 인증정보를 담은 쿠키를 전송
- 클라이언트는 전달받은 쿠키를 요청과 같이 전송하여 Stateless한 인터넷 연결을 Stateful하게 유지
- 하지만 기본적으로 쿠키는 오랜 시간 동안 유지될 수 있고, 자바스크립트를 이용해서 쿠키에 접근할 수 있기 때문에 쿠키에 민감한 정보를 담는 것은 위험
*만약 해당 인증정보를 탈취하여 서버에 요청을 보낸다면 서버는 누가 요청을 보낸 건지 상관하지 않고 인증된 유저의 요청으로 취급하기 때문에, 개인 유저 정보 같은 민감한 정보에 접근이 가능
Session
- 서버와 클라이언트 간 연결이 활성화된 상태를 의미
*사용자가 인증에 성공한 상태
- 서버는 일종의 저장소에 세션을 저장 : 세션 스토어(redis 등과 같은 트랜잭션이 빠른 DB)
1. 세션기반 인증 (Session-based Authentication)
1) 로그인
로그인 조건
- 서버는 사용자가 인증에 성공했음을 알고 있어야 함
- 클라이언트는 인증 성공을 증명할 수단을 갖고 있어야 함
- 서버는 Client에 유일하고 암호화된 ID를 부여(중요 데이터는 서버에서 관리)
- 암호화된 ID : 각 세션을 구분할 수 있는 Session Id로 클라이언트에서 세션 성공을 증명할 수단이 됨
*사이트에서 로그인을 유지하기 위한 수단으로 쿠키를 사용, 쿠키에는 서버에서 발급한 Session Id가 저장됨(Session Id가 담긴 쿠키는 클라이언트에 저장)
- 상대적으로 보안에 취약한 쿠키는 경우에 따라 자바스크립트로 접근이 가능하기에 Session Id는 암호화 과정이 필요
- 쿠키를 통해 유효한 세션 아이디가 서버에 전달되고, 세션 스토어에 해당 세션이 존재한다면 서버는 해당 요청에 접근 가능하다고 판단
- 쿠키에 세션 아이디 정보가 없는 경우, 서버는 해당 요청이 인증되지 않았음을 알려줌
2) 로그아웃
로그아웃 조건
- 서버의 세션 정보를 삭제해야 함
- 클라이언트의 쿠키를 갱신해야 함
- 서버가 클라이언트의 쿠키를 임의로 삭제할 수는 없음
set-cookie
로 세션 아이디의 키값을 무효한 값으로 갱신해야 함
2. 문제점
- 서버의 메모리에 Session 정보를 저장하고 있기 때문에 이용자가 많아질 경우 가용 메모리의 양이 줄어 서버 성능 저하
- 기존 쿠키 인증 방식을 완전히 대체한 것이 아니기 때문에 XSS 공격으로 인해 세션 쿠키가 탈취될 수 있음(탈취될 경우 서버는 해당 요청이 인증된 사용자의 요청이라고 판단)
*쿠키의 단점을 여전히 가지고 있음
3. express-session
express-session
: 세션을 위한 미들웨어로 Express에서 세션을 다룰 수 있는 공간을 보다 쉽게 만들어 줌
*세션을 대신 관리해주는 모듈
- 필요한 경우 세션 아이디를 쿠키에 저장하고, 해당 세션 아이디에 종속되는 고유한 세션 객체를 서버 메모리에 저장
*세션 객체는 서로 독립적인 객체이므로 각각 다른 데이터를 저장할 수 있음
req.session
이 바로 세션 객체이며 req.session
은 세션 객체에 세션 데이터를 저장하거나 불러오기 위해 사용
Cookie VS Session
1. Cookie
- 접속 상태 저장 경로 : 클라이언트
- 장점 : 서버에 부담을 덜어줌
- 단점 : 쿠키 그 자체는 인증이 아님
- 쿠키는 그저 http의 stateless한 것을 보완해주는 도구
2. Session
- 접속 상태 저장 경로 : 서버
- 장점 : 신뢰할 수 있는 유저인지 서버에서 추가로 확인 가능(보안에 유리)
- 단점 : 하나의 서버에서만 접속 상태를 가지므로 분산에 불리
- 접속 상태를 서버가 가지며(Stateful), 접속 상태와 권한 부여를 위해 세션 아이디를 쿠키로 전송