인증 vs 인가
인증 : 로그인, 내가 서비스의 권한을 가지고 있다는 것을 확인받는다.
인가 : 이미 인증을 받은 사용자가 서비스의 여러 기능을 사용하기 위해 자신의 권한을 사용하는 일. 로그인 후 일어나는 일
그럼 매번 요청을 보낼때마다 아이디와 패스워드를 같이 보내서 인증과 인가를 한번에 해결할 수는 없는가?
⇒ 보안상 위험하기도 하고 로그인에 필요한 암호화, 데이터베이스 통신 등등 다양한 검증 과정이 꽤 비용이 크기 때문에 이러한 방식은 비효율적이다. 따라서 쿠키, 세션, jwt 등의 다양한 방식을 활용하여 인증과 인가를 분리한다.
우선 JWT를 알아보기 전에 서버에서 자주 사용되는 세션을 간단히 이해하면 좋다.
Session
세션은 서버에서 인증을 관리하는 것을 의미한다. 세션이랑 표를 끊어서 반쪽은 쿠키로 브라우저에 전달하고, 반쪽은 서버에 저장한다.(메모리, HDD, DB) 만약 요청에 쿠키가 함께 포함되면 이를 확인하고 요청을 거부할지 수락할지 결정한다.
보통은 메모리에 올려놓는다. 그런데 문제는 메모리상 올라가게 되면 사용자가 많이 접속할때 메모리가 부족해지고, 서버에 문제가 있어서 사라지는 경우 해당 세션이 전부 사라진다.
그런데 하드나 DB에 저장하는 경우 매번 값을 들고오는 비용이 발생한다. 또한 분산 서버로 두는 경우 각자의 DB가 세션을 저장하는 위치가 달라서 로드밸런싱하는 경우 이미 세션을 발급받았지만 다른 서버에서 또 발급받아야하는 문제가 발생한다.
따라서 공용 DB로 두거나 redis같은 인메모리 DB를 사용하여 해결한다. 따라서 이러한 고민을 해결하기 위해 JWT가 나왔다.
JWT (Json Web Token)
JWT는 .을 기준으로 헤더(header) - 내용(payload) - 서명(signature)으로 이루어져 있다.
헤더
-type: jwt
-alg: 암호화 알고리즘
페이로드(base64로 디코딩하면 json형태로 존재)
-사용자 닉네임
-서비스상의 레벨
-관리자 여부
-발급자
-유효기간
⇒ 이러한 사용자의 정보를 Claim이라고 한다.
서명(Signature)
헤더와 페이로드를 서버의 개인키로 암호화하여 서명과 비교한다.만약 일치하는 경우 서버에서 암호화된 토큰이기 때문에 인가를 허용한다.
예제 코드
private String secretKey = "privateKey";
public String createToken(String userPk, List<String> roles){
//user 구분을 위해 Claim에 User Pk값 넣어줌
Claims claims = Jwts.claims().setSubject(userPk);
claims.put("roles", roles);
// 생성날짜, 만료 날짜를 위한 Date
Date now = new Date();
return Jwts.builder()// 토큰에 다양한 데이터를 넣고 압축한다.
.setClaims(claims)
.setIssuedAt(now)
.setExpiration(new Date(now.getTime() + tokenValidMillisecond))
// 개인키로 바로 서명한다.
.signWith(SignatureAlgorithm.HS256, secretKey)
.compact();
}
JWT는 비대칭키를 사용하는 것인가? 아니면 대칭키를 사용하는 것인가?
⇒ HS256을 사용하면 대칭키로 동작
개인키로 암호화하여 서명 생성하고, 개인키로 서명을 복호화하여 헤더와 페이로드 비교
⇒ RS256(RSA + SHA256) , ES256(ECDH + SHA256) 을 사용하면 비대칭키로 동작
공개키로 암호화하여 서명 생성하고, 개인키로 서명을 복호화하여 헤더와 페이로드 비교
비대칭키가 보안에 좀더 안전하다.
래퍼런스
'스프링 부트 REST API 개발일지' 카테고리의 다른 글
[Redis] 조회수를 캐시를 적용했지만 속도가 느린 문제 해결 (0) | 2022.05.27 |
---|---|
[스프링] spring MVC life cycle (0) | 2022.04.25 |
[SpringBoot] DTO를 어떻게 관리해야할까? (0) | 2022.04.05 |
[고민] public repository에 application.properties(.yml)의 정보를 어떻게 관리해야할까? (0) | 2022.03.11 |