notes
multi domain - auto ( with.cookies)
멀티 도메인 환경의 쿠키 공유·자동 설정과 보안 주의점 메모.
네이버에 한 번 로그인하면 메일, 블로그, 부동산에 들어가도 로그인이 그대로다. 회사 프로젝트도 서비스마다 서브도메인을 나눠 쓸 예정이라, JWT를 쿠키로 공유하는 방식을 따로 정리해 두었다.
- 로그인 서버가 쿠키를
Domain=example.com으로 굽으면 모든 서브도메인 요청에 같은 쿠키가 따라간다. - 각 서비스는 쿠키 안의 JWT를 서버에서 검증만 하면 되고, 쿠키는 HttpOnly와 Secure로 막아 둔다.
- 도메인 자체가 다르면 쿠키 공유는 안 되고 리다이렉트 방식 인증이 필요하다.
한 번 로그인으로 여러 서비스에
원리는 단순하다. 로그인을 담당하는 서버가 쿠키를 굽을 때 Domain을 부모 도메인으로 잡아 둔다. 그러면 브라우저는 mail.example.com이든 blog.example.com이든 요청할 때마다 그 쿠키를 알아서 실어 보낸다.
네이버도 로그인 쿠키가 .naver.com 범위로 잡혀 있어서 서비스를 옮겨 다녀도 로그인이 유지되는 거였다.
쿠키 범위와 속성
Domain을 아예 안 주면 쿠키는 만든 호스트에만 붙는다. 여기서 처음에 헷갈렸다. auth.example.com에서 로그인했는데 다른 서브도메인에서 쿠키가 안 보였던 게 이 이유였다.
응답 헤더는 이런 모양이 된다.
Set-Cookie: session_token=eyJhbGciOi...; Domain=example.com; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=3600
HttpOnly: 스크립트에서 못 읽게 해서 XSS로 토큰이 새는 걸 막는다.Secure: HTTPS에서만 전송된다.SameSite=Lax: 서브도메인끼리는 같은 사이트로 보기 때문에 Lax로도 쿠키가 간다. 다른 사이트에서 마음대로 보내는 POST는 막아 주므로 CSRF도 어느 정도 줄어든다.Max-Age: 토큰 만료와 비슷하게 맞춰 둔다.
부모 도메인에 구운 쿠키는 모든 서브도메인이 받는다는 것도 같이 기억해야 한다. 외부 업체에 맡긴 서브도메인이 있으면 거기에도 토큰이 간다.
// auth 서버: 로그인 성공 후
res.cookie('session_token', jwt, {
domain: 'example.com',
path: '/',
httpOnly: true,
secure: true,
sameSite: 'lax',
maxAge: 60 * 60 * 1000,
});
// 각 서비스: 미들웨어에서 검증
function auth(req, res, next) {
const token = req.cookies.session_token;
if (!token) return res.status(401).end();
try {
req.user = jwt.verify(token, PUBLIC_KEY, { algorithms: ['RS256'] });
next();
} catch {
res.status(401).end();
}
}검증용 키는 서비스마다 나눠 줘야 하니까 RS256처럼 공개키로 검증하는 방식이 편하다. 비밀키는 auth 서버만 갖고 있다.
API가 api.example.com처럼 따로 있으면 프론트에서 fetch(url, { credentials: 'include' })로 보내고, 서버는 Access-Control-Allow-Credentials: true와 정확한 Origin을 돌려줘야 쿠키가 실린다. Origin을 *로 두면 안 된다.
로그아웃과 다른 도메인
로그아웃할 때는 쿠키를 만들 때와 같은 Domain, Path로 지워야 한다. 하나라도 다르면 다른 쿠키로 취급돼서 안 지워진다.
res.clearCookie('session_token', { domain: 'example.com', path: '/' });
JWT는 쿠키를 지워도 토큰 자체는 만료 전까지 유효하다. 그래서 access 토큰은 짧게 가져가고, refresh 토큰이나 세션 ID는 서버에 저장해 두고 로그아웃 때 같이 폐기하는 쪽으로 잡았다.
서비스 도메인이 아예 다르면(a.com과 b.com) 쿠키는 절대 공유되지 않는다. 이때는 인증 서버로 리다이렉트해서 코드를 받아 오는 OAuth, OIDC 같은 흐름이 필요하다.