::Google의 서드 파티 쿠키 제한확대
https://developers.google.com/privacy-sandbox/cookies?hl=ko#report-issues
::Cookie
사용자가 방문한 웹사이트에서 사용자의 브라우저에 접속하는 임시 파일.
사이트에서 쿠키로 사용자의 정보를 기억하기 때문에, 다음에 해당 사이트에 들어가면 그 웹사이트가 기억하고 있는 정보를 띄워줘서 개인화된 서비스가 가능합니다. 사용자가 최근에 본 상품 리스트를 보여주는 경우가 예시가 될 수 있습니다.
::Privacy Sandbox(개인 정보 보호 샌드박스)
구글의 쿠키 제한.
쿠키를 구글은 왜 제한하는 이유는 바로 서드 파티(3rd party) 쿠키 때문입니다.
서드 파티 쿠키란 사용자가 방문한 웹사이트에 웹사이트 소유자가 아닌 제 3자가 해당 웹사이트에서 사용자의 행태를 기록, 추적하는 것입니다. 웹사이트 소유자가 고객에 대해 직접 모으는 데이터인 퍼스트 파티(1st party) 쿠키와는 달리 제3자가 고객의 데이터를 모으는 행위를 말합니다.
#️⃣출처 : https://stibee.com/api/v1.0/emails/share/b-C_tHu_wCSKVq_W1DMl5OcLLmn-VQ==
최근 로그아웃, 유저토큰재발급 서비스를 구현하면서 헤더에 쿠키 설정을 하고있었는데요.
- 로그아웃 시 헤더의 쿠키 삭제(쿠키 만료 시간을 0으로 설정),
- 유저토큰재발급 시 헤더에 토큰을 저장
쿠키 설정이 제대로 저장되지 않고 있어서, 위의 API 서비스를 호출할 때마다 에러가 발생했습니다.
로그아웃 API
AS-IS
@ApiOperation(value="23. 로그아웃", notes = "응답 헤더 쿠키 내의 토큰 제거를 위한 로그아웃 기능",
produces = "application/json", response = CommonsRes.class)
@ApiResponses({
@ApiResponse(code = 200, message = "", response = CommonsRes.class)
})
@PostMapping("/logout")
@LogTracer(apiAppType = "postman", logType = "API", apiClass = "00_21_TEST", svcClass = "JSON")
public ResponseEntity<Response> logout(HttpServletResponse httpRes) throws Exception {
// 쿠키 초기화
Cookie cookie = new Cookie("refresh-token", null);
cookie.setMaxAge(0);
cookie.setMaxAge(0); // 쿠키 만료 시간 0으로 설정하여 삭제
cookie.setPath("/"); // 쿠키의 경로를 정확하게 설정 (쿠키가 생성된 경로)
cookie.setHttpOnly(true); // 기존 쿠키가 httpOnly 속성을 가지고 있었다면 동일하게 설정
cookie.setSecure(true); // 기존 쿠키가 secure 속성을 가지고 있었다면 동일하게 설정
cookieRes.addCookie(refreshTokenCookie);
Response response = ReturnResponse.builder()
.rsp_cd(HttpResponseStatus.SUCCESS.getResCode())
.rsp_msg(HttpResponseStatus.SUCCESS.getDescription())
.build();
log.info(CommonUtil.responseToResponseBody(response));
return new ResponseEntity<Response>(response, HttpStatus.OK);
}
위의 쿠키 설정만으로, 쿠키가 저장되지 않는 이유를 확인해보니
크롬 버전이 업데이트 되면서, 크롬의 SameSite 기본값이 None -> Lax로 업데이트 되었고.
SameSite가 Lax로 설정되면, 다른 도메인 주소간의 요청에서 쿠키를 담아주지 않는다는 것이었다.
(현재 개발중인 서비스에서는 프론트 도메인에서 -> API 도메인 으로 요청을 보내고 있어서 쿠키가 담기지 않은것)
TO-BE
@ApiOperation(value="23. 로그아웃", notes = "응답 헤더 쿠키 내의 토큰 제거를 위한 로그아웃 기능",
produces = "application/json", response = CommonsRes.class)
@ApiResponses({
@ApiResponse(code = 200, message = "", response = CommonsRes.class)
})
@PostMapping("/logout")
@LogTracer(apiAppType = "postman", logType = "API", apiClass = "00_21_TEST", svcClass = "JSON")
public ResponseEntity<Response> logout(HttpServletResponse httpRes) throws Exception {
// 쿠키 초기화
Cookie cookie = new Cookie("refresh-token", null);
cookie.setMaxAge(0);
cookie.setMaxAge(0); // 쿠키 만료 시간 0으로 설정하여 삭제
cookie.setPath("/"); // 쿠키의 경로를 정확하게 설정 (쿠키가 생성된 경로)
cookie.setHttpOnly(true); // 기존 쿠키가 httpOnly 속성을 가지고 있었다면 동일하게 설정
cookie.setSecure(true); // 기존 쿠키가 secure 속성을 가지고 있었다면 동일하게 설정
List<String> domains = Arrays.asList(
"domainSite.com:8080",
"domainSite.com:38443",
"domainSite.com"
);
// 각 도메인에 대해 쿠키 설정
for (String domain : domains) {
cookie.setDomain(domain);
String cookieHeader = String.format(
"%s=%s; Max-Age=%d; Path=%s; Domain=%s; HttpOnly; Secure; SameSite=Strict",
cookie.getName(),
cookie.getValue(),
cookie.getMaxAge(),
cookie.getPath(),
cookie.getDomain()
);
httpRes.addHeader("Set-Cookie", cookieHeader);
}
Response response = ReturnResponse.builder()
.rsp_cd(HttpResponseStatus.SUCCESS.getResCode())
.rsp_msg(HttpResponseStatus.SUCCESS.getDescription())
.build();
log.info(CommonUtil.responseToResponseBody(response));
return new ResponseEntity<Response>(response, HttpStatus.OK);
}
위와 같이 코드를 수정하여 쿠키를 저장할 수 있도록 해결하였습니다.
수정한 부분은 쿠키 헤더 설정을 추가하여 SameSite=Strict로 변경하고, 각 사이트 주소를 명시한 것.
SameSite=None으로 설정하면 Domain 설정 없이도 아래와 같이 처리도 가능하지만 보안이 취약해 질 수 있습니다.
@ApiOperation(value="23. 로그아웃", notes = "응답 헤더 쿠키 내의 토큰 제거를 위한 로그아웃 기능",
produces = "application/json", response = CommonsRes.class)
@ApiResponses({
@ApiResponse(code = 200, message = "", response = CommonsRes.class)
})
@PostMapping("/logout")
@LogTracer(apiAppType = "postman", logType = "API", apiClass = "00_21_TEST", svcClass = "JSON")
public ResponseEntity<Response> logout(HttpServletResponse httpRes) throws Exception {
// 쿠키 초기화
Cookie cookie = new Cookie("refresh-token", null);
cookie.setMaxAge(0);
cookie.setMaxAge(0); // 쿠키 만료 시간 0으로 설정하여 삭제
cookie.setPath("/"); // 쿠키의 경로를 정확하게 설정 (쿠키가 생성된 경로)
cookie.setHttpOnly(true); // 기존 쿠키가 httpOnly 속성을 가지고 있었다면 동일하게 설정
cookie.setSecure(true); // 기존 쿠키가 secure 속성을 가지고 있었다면 동일하게 설정
String cookieHeader = String.format(
"%s=%s; Max-Age=%d; Path=%s; HttpOnly; Secure; SameSite=None",
cookie.getName(),
cookie.getValue(),
cookie.getMaxAge(),
cookie.getPath()
);
httpRes.addHeader("Set-Cookie", cookieHeader);
Response response = ReturnResponse.builder()
.rsp_cd(HttpResponseStatus.SUCCESS.getResCode())
.rsp_msg(HttpResponseStatus.SUCCESS.getDescription())
.build();
log.info(CommonUtil.responseToResponseBody(response));
return new ResponseEntity<Response>(response, HttpStatus.OK);
}
:: 참고
https://brunch.co.kr/@biginsight/69
'Coding > Back-end' 카테고리의 다른 글
IntellijJ에서 키보드 입력이 안 될 때 :: 시도해 볼 수 있는 방법 (0) | 2024.11.25 |
---|---|
코드컨벤션 적용 (0) | 2024.10.30 |
[postgreSql] 한 컬럼의 여러 row를 하나 값으로 합치기 | array_agg, array_to_string (0) | 2023.11.13 |
[postgreSql] 반올림 함수 모음 round, ceil, floor (0) | 2023.11.07 |
[postgreSql] WITH절로 복잡한 join 쿼리를 대신하기 (0) | 2023.10.27 |