공부한것들을 정리하는 블로그 입니다.
요청헤더 쿠키의 크기로 인한 이슈 발생 및 조치(노티서비스. 가맹점 400 오류응답. 쿠키와 세션) 본문
* 해당 글은 계속 수정 예정입니다.
최초 작성일 2022.05.10
마지막 수정일 2023.04
# 노티서비스에서 이슈 발생
승인결과를 보내주는 노티(알림)서비스가 특정 가맹점에 400 오류응답을 하고 있다고 가정해보자.
아마 모니터링에서 감지되는것이 아니라면, 가맹점에서 먼저 확인요청이 들어올 수도 있다.
400 에러는 클라이언트 에러이므로 결국 가맹점 서버에서 오류응답 한 것이다.
(4xx : 클라이언트 에러, 5xx : 서버 에러)
그러면 해당 이슈는 무조건 가맹점측 서버 문제일까?
# 상황 설명
1. 클라이언트로 부터 결제승인 요청
2. 비즈니스 로직 처리 후 외부 API 호출
원천사/중계사 통신하여 승인요청
3. 외부 API 통신 결과에 따라 클라이언트로 응답
성공, 실패, 타임아웃 등
4. 클라이언트로 응답
결제승인 요청에 대한 응답 => 성공 OR 실패
5. (비동기)클라이언트로 승인결과 노티
결제승인 요청에 대한 응답 => 성공 OR 실패
# 400 오류응답 사유
위 "5. (비동기)클라이언트로 승인결과 노티" 에서 400 오류응답을 받게 된다면,
400 오류응답의 사유는 여러가지가 있을 것이다.
이 중에서 쿠키와 세션으로 인한 이슈에 대해서 이야기 하겠다.
말하자면, 요청헤더에 쿠키의 크기가 문제가 되어 가맹점 서버에서 400 오류응답을 하는 경우이다.
# 요청/응답 전문
GET /api명칭.asp?쿼리스트링 HTTP/1.1
Content-Type: application/x-www-form-urlencoded;charset=euc-kr
Host: ip주소
Connection: Keep-Alive
User-Agent: Apache-HttpAsyncClient/4.1.1 (Java/1.8.0_212)
Cookie: ASPSESSIONID값1=값2; ASPSESSIONID값3=값2;
(JAVA면 JSESSIONID)
HTTP/1.1 400 Bad Request
Content-Type: text/html; charset=us-ascii
Server: Microsoft-HTTPAPI/2.0
Date: Tue, 10 May 2022 00:43:38 GMT
Connection: close
Content-Length: 346
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4">
<HTML><HEAD><TITLE>Bad Request</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Bad Request - Request Too Long</h2>
<hr><p>HTTP Error 400. The size of the request headers is too long.</p>
</BODY></HTML>
# 문제 해결 과정
1. 클라이언트(서비스제공자 서버) -> 서버(가맹점 서버)
http request 요청
요청헤더(Connection 헤더) Connection: Keep-Alive
=>
(*** 1.서비스제공자 서버에서 가맹점 서버로 HTTP1.1에서 제공하는 Keep-Alive 사용(HTTP1.1에서는 디폴트옵션))
(*** HTTP통신의 특성인 비연결지향(Connectionless)지만 위 방식을 통해 Connection을 유지함)
(*** Connection을 유지하면 매번 연결때마다 새로 TCP연결을 수립하고 해제하는 것을 반복하는 오버헤드가 줄어서 성능 개선 가능(Persistent Connection 설정 - 커넥션 재사용))
2. 클라이언트(서비스제공자 서버) <- 서버(가맹점 서버)
응답
응답헤더 Set-Cookie: ASPSESSIONID=xxx; path=yyy ...
=>
(*** 2.가맹점 서버에서 쿠키 만료시간을 설정하지 않고 보냄)
(*** 쿠키의 기한이 정해져 있지 않기 때문에 세션쿠키(Session Cookie)에 저장되고, 명시적으로 지우지 않는다면 반영구적으로 쿠키가 남아있게 된다.)
(*** 만료시간이 지정되지 않으면 세션쿠키(Session Cookie)에 저장되고(메모리에 있는 동안 유효-반영구적, 브라우저의 메모리에 저장(보안유리)), 지정되면 프로세스가 종료되더라고 유지되도록 지속쿠키(Persistent Cookie - 파일로 저장(보안취약))에 저장된다)
3. 클라이언트(서비스제공자서버) -> 서버(가맹점 서버)
요청
요청헤더 Cookie: ASPSESSIONID=xxx; ASPSESSIONID=xxx2; ASPSESSIONID=xxx3; ....
=>
(*** 3.서비스제공자 서버에서 명시적으로 쿠키를 지우고 있지 않기에 매번 요청헤더 내 쿠키에 세션id가 점점 쌓인채로 요청하게 됨)
(*** 클라이언트(서비스제공자 서버)는 서버로부터 응답받은 쿠키를 클라이언트(브라우저) 쿠키저장소에 저장하고 있음)
(*** 이후 서버에 요청할 때, 전달받은 쿠키를 자동으로 요청헤더에 추가하여 요청함(브라우저에서 처리해주는 작업임))
(*** 위의 2에서 쿠키의 기한이 정해져 있지 않았기에 세션쿠키(Session Cookie)에 저장되며, 명시적으로 쿠키를 지우고 있지 않기 때문에 매번 요청헤더 내 쿠키에 세션id가 점점 쌓임)
(*** 클라이언트의 브라우저가 서비스제공자의 서버인데, 세션쿠키(Session Cookie)는 브라우저의 메모리에 저장되므로)
4. 클라이언트(서비스제공자 서버) <- 서버(가맹점 서버)
응답
상태 HTTP/1.1 400 Bad Request
응답헤더 Connection: close
응답바디 내용(<hr><p>HTTP Error 400. The size of the request headers is too long.</p>)
=>
(*** 4.쿠키는 클라이언트에 최대 300개까지 저장되고, 서버 도메인 하나당 20개가 저장되며, 하나의쿠키 값은 최대 4KB까지 저장이 가능하다.)
(*** 요청헤더의 경우 길이가 제한적이기에, 가맹점에서는 늘어난 세션ID가 들어있는 쿠키의 사이즈가 너무 커져서 오류응답함)
5. 클라이언트(서비스제공자 서버)에서의 해결방안
=>
2. 클라이언트(서비스제공자 서버) <- 서버(가맹점 서버)
1) 쿠키 설정에서 만료시간(expires를 추가하여 보낸다)
3. 클라이언트(서비스제공자 서버) -> 서버(가맹점 서버) 에서의 방법들
1) 쿠키 제한 설정(쿠키 관리 : 명시적으로 쿠키 제거, 이전 세션ID 제거 등)
=>
가맹점 서버의 설정을 바꿀순 없으므로, 3 에서 쿠키 제한 설정을 통해 해결함
# 쿠키와 세션
1. 클라이언트 -> 서버
최초 요청시에 클라이언트 정보를 보냄
클라이언트가 로그인을 하면 서버는 회원정보를 대조하여 '인증'을 진행
2. 클라이언트 <- 서버
서버는 클라이언트 정보를 세션저장소에 생성하고 세션ID를 발급
발급한 세션ID를 HTTP RESPONSE HEADER 쿠키에 담아서 클라이언트로 전송
set-cookie
클라이언트에서는 세션ID를 쿠키저장소에 저장하고 이후 HTTP REQUEST를 보낼 때마다 SESSION ID를 쿠키에 담아서 전송
cookie sessionid
3. 클라이언트 -> 서버
서버에서는 쿠키에 담겨져서 온 세션ID에 해당하는 회원정보를 세션 저장소에서 가져옴('인가')
4. 클라이언트 <- 서버
응답메시지에 회원정보를 바탕으로 처리된 데이터를 담아서 클라이언트에 전송
# 추가 공부
# http의 특성 : connectless & stateless (비연결성 & 무상태성)
## 동일한 클라이언트로부터 연속적으로 요청이 있는 경우
### keep-alive하지 않은 경우 : 연속적인 작업에 연결을 맺고 끊는 과정이 각각 들어간다.
(요청a)
클라이언트와 서버가 연결을 맺는다
서버가 요청a를 처리한다
클라이언트와 서버의 연결이 끊어진다.
(요청b)
a의 결과를 가지고 클라이언트가 서버에 요청을 맺는다
클라이언트와 서버가 연결을 맺는다
서버가 요청b를 처리한다
클라이언트와 서버의 연결이 끊어진다
### keep-alive한 경우
(요청a와 요청b를 한 연결로)
클라이언트와 서버가 연결을 맺는다
서버가 요청a를 처리한다
클라이언트가 요청a의 결과를 가지고 요청b를 요청한다
서버가 요청b를 처리한다
클라이언트와 서버의 연결이 끊어진다
=> 서버입장에서는 연결을 유지하고 있기 때문에 어느 순간 가능한 연결을 다 써버릴 수 있고 더이상 연결 요청을 받을 수 없다는 것을 주의
=> keep-alive 옵션을 사용할 때는 몇 초간 유지될지 or 최대 몇개의 요청을 수용할 것인지 정한다.
ex) Response Header에서 Keep-Alive:timeout=10, max=200와 같이 확인 가능하며 요청마다 max가 하나씩 감소한다.
# 참고
쿠키(cookie) vs 세션(session)
https://velog.io/@corone_hi/%EC%BF%A0%ED%82%A4-vs-%EC%84%B8%EC%85%98
[HTTP] HTTP 이해하기 (2) / Session, Cookies, Keep-Alive
https://happynotepad.tistory.com/50
https://happynotepad.tistory.com/49?category=893034
자바스크립트 쿠키 저장 및 관리 총정리
https://blogpack.tistory.com/1071
쿠키 & 세션
https://velog.io/@godkimchichi/Java-18-Servlet-%EC%BF%A0%ED%82%A4-%EC%84%B8%EC%85%98
(★추천. 필요한 만큼만 딥하게 잘 설명되어 있음)
Web - 쿠키와 세션의 차이, 용도, 사용법(cookie,session)
https://jeong-pro.tistory.com/80
# 참고2
1. 본인 블로그 : (참고사례)
https://drsggg.tistory.com/749
'경력 실무경험 > 실무 주제' 카테고리의 다른 글
DB 시퀀스를 통한 일련번호 채번 시 주의(중복채번, 다중DB) (0) | 2023.04.27 |
---|---|
DB 날짜데이터 Insert시 반드시 정합성 체크를 할 것(DB Select 오류 ORA-01847 : 달의 날짜는 1에서 말일 사이여야 합니다) (0) | 2023.04.26 |
DB동기화 점검(지연발생)시 고려사항(개설기관 장애 응답) (0) | 2023.04.26 |
외부API 장애 발생과 대응 예상(카드사 TIMEOUT과 PG/VAN 대응) (0) | 2023.04.26 |
레거시 서버 장비노후 이슈 발생 및 조치 (0) | 2023.04.26 |
배치컨테이너 배포와 스케줄러 실행이 동시에 진행되는 것에 주의(InvalidGlobalDeployVersionException, InvalidGlobalDeployVersion, LinkageError) (0) | 2023.04.25 |
계좌이체 서비스의 은행점검시간으로 인한 딜레이 발생시 해결방안 (은행사 시스템취소) (0) | 2023.04.25 |
SimpleDateFormat 사용시 주의사항 (년도 포맷 주의사항) (0) | 2023.04.25 |