세션은 stateless를 기본으로하는 HTTP 프로토콜 환경에서, 사용자와 서버의 논리적 연결을 위한 장치다.
HTTP 프로토콜을 사용하면, 서버는 리퀘스트를 처리한 후에 이 state를 별로로 보관해서 유저별로 관리하는 것이 아니기 때문에, 클라이언트가 연속된 동작을 할 수 없게 된다.
예를 들어, 특정 사용자가 로그인을 통해 인증 받고 화면에 접속하게 된 후에, 다른 리퀘스트를 보내면 서버는 현재 이 사용자가 정상적으로 로그인 상태인지 여부를 알 수 없어 다시 로그인을 요청 할 수 밖에 없다.
이런 문제를 막기 위해서 클라이언트는 서버에게 세션을 활용해서 논리적 연결성을 유지한다.
과거에는 쿠키가 이런 역할을 대신 했지만, 쿠키를 사용하는 방식은 보안이 취약하기 때문에 세션이 등장했다.
세션을 설명하기 전에 쿠키를 통한 통신 방법을 간략하게 살펴보자.
유저가 로그인을 통해 인증 받는 방식을 예로 들겠다.
<이미지 출처 : https://www.cookieyes.com/blog/session-cookies/ >
세션의 동작 방식도 매우 유사하다.
세션도 쿠키를 사용하지만, 쿠키에 사용자 데이터 자체를 넣는 것이 아니라 세션 id를 넣는다는 점이 다르다.
동작 방식은 위에서 소개한 쿠키를 이용한 방식과 동일하지만, 쿠키 값 안에 사용자 정보나 요청내용을 넣는 것이 아니라, 세션 id 값을 넣어서 관리한다.
이 세션 id는 서버에서 발급하는 것으로, 요청이 있을 때 유니크한 암호화 된 값을 생성해서 클라이언트에 전달한다. 이 값은, 서버 내부에서 사용자 정보와 매핑돼서 관리한다.
<이미지 출처 : http://jun.hansung.ac.kr/SWP/PHP/PHP%20Sessions.html>
그럼 브라우저가 아닌 모바일 앱에서는 세션 관리가 필요할까?
결론부터 말하면, 모바일 환경에서도 세션과 유사한 방식을 사용할 수 있지만, 잘 사용하지는 않는다.
HTTP 프로토콜을 사용하면, 결국 논리성의 연속성을 유지하기 위해서 세션과 비슷한 개념이 모바일에도 필요하다. 하지만, 세션이나 쿠키와 같은 방식을 주로 사용하지는 않는 것으로 알고 있다.
모바일과의 네트워킹에서 브라우저에서의 세션과 다른 방식이 사용되는 이유는 다음과 같다.
웹에서는 세션을 발급 받으면, 이를 쿠키에 넣어두고 다시 서버와 소통할 때 사용한다.
하지만, 앱은 그 자체로 파일 시스템에 엑세스 할 수 있을 뿐 아니라, 내부 DB도 가질 수 있기 때문에 쿠키를 통해 통신할 필요가 없다.
서버에서 받은 유저 식별 데이터를 따로 저장해서 통신할 때 사용하면 된다. 이 값은 보통 앱이 종료되고 재실행 돼도, 로그아웃하지 않는 이상 지워지거나 갱신되지 않는다.
즉, 동작 방식은 동일하지만, 세션처럼 관리될 필요는 없는 것이다.
TTL을 따로 설정할 필요가 없고, 세션같이 종료시에 expire 될 필요도 없다.
또한 앱에서는 모든 정보를 서버에게 요청하는 것이 아니라, 많은 양 클라에서 가지고 있고 서버에서 받은 내용도 캐싱 되는 경우가 대부분이기 때문에, 논리적 연결성 또한 기본적으로 성립되어 있다.
브라우저에서는 기본적으로 경로가 주소에 공개되어 있고, 환경 자체가 쿠키 값을 파악하거나 중간 탈취할 가능성이 크기 때문에, 세션을 사용하는 것이 필요하다.
하지만 앱은 기본적으로 사용자와 1대1 매칭되며, 정보 탈취 가능성이 낮기 때문에 해당 방식과 유사한 방법을 사용한다.
*단, 웹뷰등으로 구현하는 하이브리드 앱에서는 세션 관리가 필요하다.
중간 탈취 가능성이 적다고 하더라도, 보안을 전혀 적용하지 않을 수는 없다.
브라우저에서 쿠키 값을 이용해서 어뷰징 할 수 있듯이
앱에서는 리버스 엔지니어링을 활용해서 api 어뷰징 할 수 있다.
(리버스 엔지니어링 관련해서는 다른 게시물에서 좀 더 자세히 다루겠다)
이런 내용을 막기 위해서 서버와 통신에 있어서 다른 장치가 필요하다.
모바일 앱을 상대로도 서버 쪽에 인증 허가가 필요한 것이다.
이때 기본적인 브라우저에서의 세션과 같은 내용을 사용하지 않기 때문에,
크게 두 가지 방법을 사용해서 리퀘스트의 유효성을 검증한다.
앱의 고유로 가지는 해쉬값을 서버로 전달한다.
apk 안의 META-INF/CERT.SF 와 같은 파일이 존재한다.
여기서 signing 및 앱 버전에 의존하는 고유 해쉬값을 추출 할 수 있다.
이 값을 서버 DB에 넣어두고 클라이언트와 서로 통일 됐을 때만 리퀘스트를 허가하는 방식으로 보안을 높일 수 있다.
(bundle에서는 code transparency를 적용시킬 수 있다)
play intergrity는 간략하게 말하자면, 앱이 실제 마켓에서 받았는지 검증하는 방식이다.
서버와 구글서버가 앱을 사이에 두고 서로 고유 값을 통해서 소통한다.
서버와 플레이 서버를 모두 거쳐서 유효성을 검증하는 방식이다.
*ios는 잘 모른다. 근데 리버스엔지니어링이 안드로이드보다 훨씬 어려운 것을로 알고 있다. 나중에 추가 조사해보겠다.