HTTP는 Connectionless, Stateless 하다는 특징이 있습니다.
- Connectionless는 클라이언트가 요청을 한 후 응답을 받으면 연결을 끊어버린다.
- Stateless는 클라이언트의 상태 정보를 가지지 않는다. 클라이언트와 첫 번째 통신에서 데이터를 주고받았다 해도, 다음에 이전 데이터를 유지하지 않는다.
우리가 페이지를 이동하더라도 로그인 상태를 유지하거나, 장바구니에 넣은 목록을 유지하는 등 데이터를 유지할 필요가 있습니다. 이 때 HTTP의 Connectionless, Stateless한 점을 보완하여 클라이언트가 누군지 확인하고, 데이터를 유지하기 위해 쿠키와 세션을 사용합니다.
쿠키와 세션에 대해서 알아보고, JSP에서 어떻게 사용하는지 알아보겠습니다.
쿠키
웹 브라우저가 보관하는 데이터
- 웹 서버와 웹 브라우저 양쪽에서 생성할 수 있다.
쿠키 동작 방식
- 쿠키 생성 단계 : JSP 쿠키는 웹 서버 측에서 생성한다. 생성한 쿠키를 응답 데이터의 헤더에 저장해서 웹 브라우저에 전송한다.
- 쿠키 저장 단계 : 웹 브라우저는 응답 데이터에 포함된 쿠키를 쿠키 저장소에 보관한다. 쿠키의 종류에 따라 메모리나 파일에 저장한다.
- 쿠키 전송 단계 : 웹 브라우저는 매번 저장된 쿠키를 Header에 포함해서 요청을 보낸다. 웹 서버는 쿠키를 사용해서 필요한 작업을 수행한다.
쿠키 구성 요소
- 이름 : 각각의 쿠키를 구별하는데 사용하는 이름
- 값 : 쿠키의 이름과 관련된 값
- 유효시간 : 쿠키의 유지시간
- 도메인 : 쿠키를 전송할 도메인
- 경로 : 쿠키를 전송할 요청 경로
이름은 보통 알파벳과 숫자만 사용한다. 유효시간 뒤에 쿠키가 삭제되고, 유효시간이 지정되어있지 않을 경우 웹 브라우저를 종료할 때 삭제된다. 지정한 도메인이나 경로로만 전송하도록 제한할 수 있다.
쿠키 생성하기
Cookie
클래스 사용
1
2
Cookie cookie = new Cookie("cookieName", "cookieValue");
response.addCookie(cookie);
- 쿠키 객체 생성
- 쿠키 추가(웹 브라우저에 쿠키 정보를 전송한다)
- 쿠키의 도메인과 경로는 도메인 간에 또는 특정 요청 경로에 위치한 JSP 간에 쿠키를 공유할 때 필요하다.
쿠키 값 변경
같은 이름의 쿠키를 새로 생성해서 응답 데이터로 보내면 된다.
- 쿠키 값 존재 여부 확인 후 처리해줘도 된다.
1
2
3
4
5
6
for(int i = 0; i < cookies.length; i++) {
if(cookies[i].getName().equals("name")) { // "name" 쿠키 값 존재 여부 확인
Cookie cookie = new Cookie("name", URLEncoder.encode("JSP프로그래밍", "utf-8"));
response.addCookie(cookie);
}
}
쿠키 삭제
유효 시간을 0으로 지정해준 뒤 응답 데이터로 보낸다.
1
2
3
Cookie cookie = new Cookie("name", "value");
cookie.setMaxAge(0);
response.addCookie(cookie);
쿠키의 도메인
- 기본적으로 쿠키는 그 쿠키를 생성한 서버에만 전송된다. www.somehost.com 👉 www.somehost.com
setDomain()
사용해서 생성한 쿠키를 전송할 수 있는 도메인을 지정할 수 있다..
점으로 시작하는 경우 관련 도메인에 모두 쿠키를 전송한다. (쿠키의 범위 확장) .somehost.com 👉 www.somehost.com / mail.somehost.com / javacan.somehost.com- 점이 아닌 문자로 시작하는 경우 해당 도메인에만 쿠키를 전송한다. www.somehost.com 👉 www.somehost.com
- 설정하지 않으면 그 쿠키를 생성한 해당 도메인에만 쿠키를 전송한다.
- 도메인에 대한 예제를 테스트할 때 C:\Windows\System32\drivers\etc 폴더의 host 파일을 수정한다. 127.0.0.1 javacan.somehost.com
도메인에 따른 쿠키의 종류
- 브라우저 쿠키
- 기본적으로 쿠키를 보낸 서버가 속한 도메인으로만 쿠키를 되돌려 보낸다. 이런 경우 해당 URL에서만 쿠키를 사용한다.
- 도메인 쿠키
- Domain 파라미터를 설정하면 서브 도메인까지 쿠키를 보내서 쿠키를 공유할 수 있게 된다.
- naver.com 으로 설정한다면 a.naver.com 또는 b.naver.com으로 보낸다.
쿠키의 경로
- 경로는 URL에서 서버 주소 이후 부분인 디렉터리 부분이다. URL : https://localhost:8080/chap09/path2/viewCookies.jsp 경로 : /chap09/path2/viewCookies.jsp
- 쿠키에서 사용하는 경로는 디렉터리 수준까지의 경로를 사용한다. 예 :
/
or/chap09
or/chap09/path2
setPath()
를 사용해서 쿠키의 경로를 지정할 수 있다.- 설정한 경로와, 하위 경로까지 전송한다. (쿠키의 범위 축소)
- 설정하지 않으면 실행한(쿠키를 보냈던) URL의 경로 부분을 사용한다.
쿠키의 유효시간
- 쿠키는 유효시간을 갖는다.
- 유효시간을 지정하지 않으면 웹 브라우저를 종료할 때 쿠키를 함께 삭제한다. 웹 브라우저 종료 후 다시 웹 브라우저를 실행하면 삭제한 쿠키는 서버에 전송되지 않는다.
- 유효시간을 지정하면 그 유효시간동안 쿠키가 존재하고, 웹 브라우저를 종료해도 유효시간이 지나지 않으면 쿠키를 삭제하지 않는다.
setMaxAge()
를 사용해서 유효시간을 지정한다.- 초 단위로 지정한다. (1시간 = 60*60)
- 아이디 기억하기 기능을 구현할 때 쿠키를 사용한다.
- 사용자가 로그인에 성공하면 아이디를 값으로 저장하고 있는 쿠키의 유효시간을 여유롭게 잡아서 생성한다. 그러면 다음에 웹 브라우저를 실행할 때 아이디를 저장하고 있는 쿠키를 사용할 수 있다.
유효기간에 따른 쿠키의 종류
- 세션(Session) 쿠키
- 브라우저를 닫으면 사라지는 쿠키(유효기간이 없다)
- 탭으로 나뉘어져있어도 쿠키가 공유된다
- 영속(Persistent) 쿠키
- 브라우저를 닫아도 유효기간까지 저장되는 쿠키
- 디스크에 저장되며 컴퓨터를 재시작해도 남아있다
- 사용자 로그인 유지에 사용된다
- Session 쿠키와 Persistent 쿠키의 차이점
- Discard 파라미터가 true(디스크에 저장)이거나, Expires(종료시점), Max-age(유효기간) 파라미터가 설정되어 있으면 Persistent 쿠키이다.
쿠키와 헤더
response.addCookie()
로 쿠키를 추가하면 Set-Cookie 헤더를 통해 전달된다.- 한 개의 Set-Cookie 헤더는 한 개의 쿠키 값을 전달한다.
- Set-Cookie 헤더의 구성
Set-Cookie: 쿠키이름=쿠키값; Domain=도메인값; Path=경로값; Expires=GMT형식의만료일시
세션
서버(웹 컨테이너)가 보관하는 데이터
- 웹 컨테이너는 기본적으로 한 웹 브라우저마다 한 세션을 생성한다. 👉 웹 브라우저와 관련된 정보를 저장하기 알맞은 장소이다.
- 같은 JSP 페이지어도 웹 브라우저에 따라 서로 다른 세션을 사용한다.
- 로그인한 사용자의 정보를 유지하기 위한 목적으로 세션을 사용한다.
세션 생성하기
- page 디렉티브의 session 속성을 true로 지정한다.
<%@ page session="true" %>
- 기본값이 true이므로 session 속성값을 false로 지정하지만 않으면 세션이 생성된다.
- 세션을 생성하면 session 기본 객체를 통해 세션을 사용할 수 있다.
- 서버 프로그램에 웹 브라우저가 처음 접속할 때 세션을 생성하고, 이후로는 이미 생성된 세션을 사용한다.
session 기본 객체
session 기본 객체는 request 기본 객체와 마찬가지로 속성을 제공하므로 메서드를 사용하여 속성값을 저장하거나 읽어올 수 있다.
메서드
메서드 | 설명 |
---|---|
String getId() | 세션의 고유 ID(세션ID)를 구한다. |
long getCreationTime() | 세션이 생성된 시간을 구한다. |
long getLastAccessedTime() | 웹 브라우저가 가장 마지막에 세션에 접근한 시간을 구한다. |
- 시간을 구할 때 1970년 1월 1일 이후 흘러간 시간을 의미하고, 단위를 1/1000초로 가져온다. 이를 보기 편하게 출력하기 위해 아래와 같은 방법을 사용한다.
1
2
3
4
Date time = new Date();
SimpleDateFormat formatter = new SImpleDateFormat("yyyy-MM-dd HH:mm:ss");
time.setTime(session.getCreateTime());
formatter.format(time);
- 웹 브라우저마다 별도의 세션을 구분하기 위해 각 세션마다 할당하는 고유 ID를 세션 ID라고 한다.
- 웹 서버가 웹 브라우저에 세션 ID를 전송한다.
- 웹 브라우저는 웹 서버에 연결할 때마다 매번 세션 ID를 보내서 웹 서버가 어떤 세션을 사용할지 판단할 수 있게 한다.
- 웹 서버와 웹 브라우저는 세션ID를 공유하기 위해 쿠키를 사용한다. (JSESSIONID 쿠키를 이때 사용한다.)
속성 사용
로그인한 회원 정보 등 웹 브라우저와 일대일로 관련된 값을 저장할 때 쿠키 대신 세션을 사용할 수 있다.
- 중요한 데이터를 저장할 때 알맞은 장소이다.
- 쿠키를 지원하지 않을 경우 사용할 수 있다.
- 여러 서버에서 공유할 수 없다.
setAttribute()
를 사용해서 속성에 값을 저장한다.
1
session.setAttribute("NAME", "김소연");
getAttribute()
를 사용해서 속성값을 읽는다.
1
String name = (String)session.getAttribute("NAME");
세션 종료
session.invalidate()
를 사용해서 세션을 종료한다.
- 현재 사용 중인 session 기본 객체를 삭제하고, 저장했던 속성 목록도 함께 삭제한다.
- 세션 종료 후 다음 요청에서 session을 사용하면 새로운 session 기본 객체를 생성한다.
세션 유효시간
세션은 최근 접근 시간을 갖는다.
- 세션을 사용하도록 설정된 JSP 페이지에 접근할 때마다 세션의 최근 접근 시간을 변경한다.
- 세션은 마지막 접근 이후 일정 시간 이내에 다시 세션에 접근하지 않는 경우 자동으로 세션을 종료하는 기능을 갖고 있다. (이후 세션을 요청하면 새로운 세션 생성)
세션 유효시간 설정하는 두가지 방법
- WEB-INF\web.xml 파일에
<session-config>
태그를 사용하여 세션 유효 시간을 지정한다. (값의 단위는 분이다.)- 0이나 음수로 설정할 경우 유효시간을 갖지 않는다.
- invalidate() 호출 전까지 세션 객체가 유지된다. 세션 객체가 메모리에 남게되어 메모리 부족 현상이 발생하게 된다. 👉 반드시 세션 타임아웃 시간을 지정해주어야 한다.
1
2
3
<session-config>
<session-timeout>50</session-timeout>
</session-config>
- session 기본 객체의
setMaxInactiveInterval()
메소드를 사용한다. (값의 단위는 초다.)
1
session.setMaxInactiveInterval(60*60);
request.getSession() 을 사용한 세션 생성
request.getSession()
은 현재 요청과 관련된 session 객체를 리턴한다.
- page 디렉티브의 session 속성값은 false로 지정한다.
- session이 이미 존재하면 해당 session을 리턴하고, 존재하지 않으면 새롭게 session을 생성해서 리턴한다.
- false 인자를 전달하면 새롭게 생성된 경우에만 session 객체를 리턴한다. (아니면 null 리턴)
세션을 사용한 로그인 상태 유지
- 로그인에 성공하면 session 기본 객체의 특정 속성에 데이터를 기록한다.
- 이후로 session 기본 객체의 특정 속성이 존재하면 로그인한 것으로 간주한다.
- 로그아웃할 경우 session.invalidate() 메소드를 호출하여 세션을 종료한다.
쿠키와 세션 비교
쿠키 | 세션 |
---|---|
- 웹 브라우저에 보관한다 - 클라이언트의 로컬에 저장되기 때문에 보안에 취약하다. - 만료 시간이 있지만 파일로 저장되기 때문에 브라우저를 종료해도 계속해서 정보가 남아있을 수 있다. - 세션보다 더 빠르다. | - 서버에 보관한다 - 쿠키를 이용해서 sessionid만 저장하고 그것으로 구분해서 서버에서 처리하기 때문에 비교적 보안성이 좋다. - 만료 시간이 있지만 브라우저가 종료되면 만료시간에 상관없이 삭제된다. - 쿠키보다 더 느리다. 서버의 처리가 필요하기 때문이다. |
세션을 사용하면 좋은데 쿠키를 사용하는 이유
세션은 서버에 보관되기 때문에 무분별하게 만들다보면 서버의 메모리가 감당할 수 없어지고 속도가 느려질 수 있기 때문이다.
쿠키의 한계
유실되기 쉽다
대부분 브라우저는 환경 설정에서 쿠키 일괄 삭제 기능을 제공하며, 웹사이트 별로도 어렵지 않게 쿠키를 삭제할 수 있다.
변조되기 쉽다
브라우저의 개발자 도구를 사용하면 각 웹사이트 별로 현재 어떤 쿠키가 저장되어 있는지 한 눈에 파악할 수 있으며 쿠키를 손쉽게 변경할 수 있다.
도난되기 쉽다
클라이언트에 저장되어 있는 쿠키가 탈취되는 것을 서버 입장에서 막을 수 없다.
쿠키의 대체기술
- 대부분의 모던 브라우저는 로컬 스토리지나 세션 스토리지와 같은 쿠키를 대체할 수 있는 웹 스토리지 기술을 지원하고 있다.
- 웹 개발의 패러다임이 백엔드에서 프런트앤드로 옮겨오면서 예전보다 많은 코드가 서버가 아닌 브라우저에서 실행되고 있습니다. 그래서 굳이 브라우저에 저장되어 있는 데이터를 서버로 전송하지 않고도 자바스크립트로 해당 데이터에 쉽게 접근할 수 있게 되었다.
이러한 웹 스토리지 기술에 비해서 쿠키의 최대 단점은 매 요청마다 같은 데이터가 서버로 전송됨에 따른 네트워크 대역폭 낭비이다.
쿠키를 사용할 수 밖에 없는 이유
이처럼 쿠키는 단점이 많지만 사용할 수 밖에 없는 이유는 HTTP 프로토콜은 연결을 유지시키지 않고(connectionless) 상태가 없는(stateless) 특성 때문이다.
쿠키를 사용하여 서버로 유입되는 요청 중에서 각각 어떤 사용자의 요청인지 판단할 수 있다.
1. 대규모 서비스에서 부하 분산
사용자들로부터 많은 요청이 들어올 때 여러 대의 서버를 사용하고, 이러한 서버 앞에는 로드 밸런서를 두어 여러 대의 서버로 부하가 분산될 수 있도록 한다. 만약 로그인한 서버와 다음 요청을 한 서버가 다르다면 그 서버에는 세션정보가 존재하지 않기 때문에 로그인 상태를 유지하기 어렵다. 이 때 서버의 ID를 쿠키로 지정하면, 로드밸런서는 이 서버 식별자를 보고 항상 동일한 서버로 요청을 보내줄 수 있다.
2. 세션 기반 사용자 인증
서버에서 세션을 생성하면 그 세션을 식별할 수 있는 식별자 (세션 ID)를 얻는다. 이 세션ID를 쿠키로 설정하면 브라우저는 요청을 보낼 때마다 세션ID를 포함한 쿠키를 서버로 돌려보낸다. 서버에서는 이 세션ID에 해당하는 세션이 있는지 확인하면 된다.
악용되는 쿠키
서드파티(Third party) 쿠키
- 브라우저로 웹사이트에 접속할 때 그 웹사이트의 도메인이 아닌 타 도메인을 상대로 적용되는 쿠키이다.
- 보통 사용자 맞춤 광고를 위해서 사용자가 어떤 웹사이트를 방문하는지 추척하는 용도로 많이 사용이 되고 있다.
캐시란?
캐시는 쿠키와 세션과 다르다.
이미지, css, js 파일 등 리소스 파일들을 사용자의 PC에 저장해놓고 로드하게 해서 서버를 거치지 않아도 된다. 다시 사용할 때 빠르게 접근할 수 있어서 페이지 로딩 속도를 개선할 수 있다.
한 번 캐시에 저장되면 브라우저를 참고하기 때문에 서버에서 변경이 되어도 사용자는 변경되지 않게 보일 수 있다. 이 때 캐시를 직접 지워주거나, 서버에서 클라이언트로 응답을 보낼 때 header에 캐시 만료시간을 명시하는 방법 등이 있다.
출처
- 최범균의 JSP 2.3 웹 프로그래밍
- https://interconnection.tistory.com/74
- https://www.daleseo.com/http-cookies/