앞 편에서 자원을 저장해 다시 받지 않게 하는 캐시를 다루었다. 이번 편에서 다루는 저장은 결이 다르다. 캐시가 서버에서 받은 자원을 재사용하기 위한 저장이라면, 이번의 저장은 사용자와 그 사용자의 상태에 관한 데이터를 브라우저 안에 담아 두기 위한 것이다. 로그인 상태를 유지하고, 장바구니를 기억하고, 화면 설정을 보관하는 이 모든 일이 이 저장 위에서 이뤄진다.


브라우저에는 이런 데이터를 담는 여러 수단이 있고, 각각 담기는 방식과 용량과 수명과 서버로 오가는지의 여부가 다르다. 이 차이를 모르면 민감한 정보를 엉뚱한 곳에 담아 위험을 자초하거나, 잘못된 수단을 골라 성능과 보안을 함께 잃는다. 각 수단이 무엇을 위해 만들어졌고 어떤 성질을 가지는지를 구분하는 것이 이번 편의 목적이다.

요청에 실려 오가는 작은 데이터

가장 오래되고 특별한 저장 수단은 요청과 함께 서버로 실려 오가는 작은 데이터다. 서버가 이 데이터를 브라우저에 심어 두라고 응답에 담아 보내면, 브라우저는 그것을 저장해 두었다가 같은 서버로 요청을 보낼 때마다 자동으로 함께 실어 보낸다. 이 자동 왕복이 이 수단의 가장 큰 특징이다.


이 왕복 덕분에 서버는 각 요청이 누구의 것인지를 알 수 있다. 통신 규약 자체는 이전 요청을 기억하지 못하므로, 서버는 이 작은 데이터를 표식 삼아 여러 요청을 같은 사용자의 것으로 묶는다. 로그인한 뒤 페이지를 옮겨 다녀도 로그인 상태가 유지되는 것이 바로 이 표식이 매 요청에 실려 오가기 때문이다. 상태를 기억하지 못하는 통신 위에서 상태를 유지하는 다리인 셈이다.


이 데이터에는 여러 속성을 붙여 그 행동을 통제할 수 있다. 언제까지 보관할지를 정하는 수명, 어떤 주소 범위의 요청에 실릴지를 정하는 적용 범위, 안전한 연결에서만 실려 가도록 하는 제한, 스크립트가 그 값을 읽지 못하게 막는 제한 등이다. 이 속성들을 어떻게 거느냐에 따라 같은 데이터도 안전할 수도 위험할 수도 있다.


특히 로그인 표식처럼 민감한 데이터에는 이 속성을 엄격히 걸어야 한다. 스크립트가 읽지 못하게 막아 두면, 페이지에 침투한 악의적 스크립트가 그 표식을 훔쳐 가는 것을 막을 수 있다. 안전한 연결에서만 실리게 해 두면 중간에서 가로채이는 위험도 줄인다. 이 데이터는 자동으로 오가는 만큼 편리하지만, 바로 그 자동성 때문에 통제를 소홀히 하면 표적이 된다.

매 요청에 실리는 대가

이 작은 데이터가 매 요청에 자동으로 실린다는 성질은 편리함의 원천이지만 동시에 대가이기도 하다. 요청을 보낼 때마다 이 데이터가 함께 실려 가므로, 저장된 것이 많고 클수록 매 요청이 그만큼 무거워진다. 화면과 무관한 자원을 받을 때조차 이 데이터가 딸려 가, 통신에 불필요한 짐을 더한다.


그래서 이 수단에는 담을 수 있는 크기에 엄격한 제한이 있고, 실제로도 꼭 필요한 최소한만 담아야 한다. 서버가 매 요청에서 확인해야 하는 표식, 곧 누구인지를 가리는 정보 정도만 담고, 그 밖의 부피 있는 데이터는 다른 수단에 두는 것이 옳다. 이 수단에 이것저것 욱여넣으면 모든 요청이 그 무게를 나눠 지게 된다.


적용 범위를 좁게 잡는 것도 이 대가를 줄이는 방법이다. 이 데이터가 실려야 할 요청의 범위를 필요한 곳으로 한정하면, 그 범위 밖의 요청에는 실리지 않아 불필요한 왕복이 사라진다. 범위를 넓게 잡아 두면 관계없는 자원을 받을 때도 데이터가 딸려 가 낭비가 된다. 범위 설정은 편의뿐 아니라 성능의 문제이기도 하다.


결국 이 수단은 서버가 매 요청에서 반드시 확인해야 하는 작고 민감한 표식을 위한 것이다. 서버가 관여할 필요 없이 브라우저 안에서만 쓰이는 데이터라면, 매 요청에 실려 서버까지 오갈 이유가 없다. 그런 데이터에는 서버로 오가지 않는 다른 저장 수단이 더 알맞다. 서버가 볼 필요가 있는지 없는지가 저장 수단을 고르는 첫 번째 기준이다.

서버로 오가지 않는 저장

브라우저에는 서버로 실려 가지 않고 브라우저 안에만 머무는 저장 수단도 있다. 이 저장에 담긴 데이터는 요청에 딸려 가지 않으므로 통신에 짐을 더하지 않는다. 그래서 서버가 볼 필요 없이 브라우저 안에서만 쓰이는 데이터, 이를테면 화면 설정이나 잠시 담아 두는 입력 내용을 두기에 알맞다.


이 수단은 앞의 것보다 담을 수 있는 용량이 훨씬 넉넉하다. 매 요청에 실리지 않으니 크기에 그렇게 엄격할 이유가 없기 때문이다. 이름과 값을 짝지어 담는 단순한 형태라 다루기도 쉽다. 스크립트가 값을 넣고 꺼내는 것이 간단해, 간단한 설정 값을 보관하는 데 널리 쓰인다.


이 저장은 수명에 따라 다시 둘로 나뉜다. 하나는 전원을 꺼도 지워지지 않고 지속되는 것이고, 다른 하나는 그 화면 탭이 열려 있는 동안만 유지되다 닫으면 사라지는 것이다. 오래 기억해야 할 설정은 지속되는 쪽에 두고, 그 방문 동안만 필요한 임시 상태는 사라지는 쪽에 둔다. 데이터가 얼마나 오래 살아야 하는지에 따라 둘을 나눠 쓴다.


다만 이 단순한 저장에는 한계가 있다. 값을 넣고 꺼내는 일이 그 순간 흐름을 잠깐 붙잡는 방식이라, 큰 데이터를 자주 다루면 화면이 끊길 수 있다. 또 이름과 값을 짝짓는 단순한 형태라 복잡하게 얽힌 데이터를 체계적으로 다루기에는 부족하다. 그래서 작고 단순한 데이터에는 알맞지만, 크고 구조적인 데이터에는 다른 수단이 필요하다.

구조적인 데이터를 담는 저장

많은 양의 구조적인 데이터를 브라우저에 담아야 할 때를 위한 저장 수단도 있다. 이것은 이름과 값을 짝짓는 단순한 형태를 넘어, 여러 항목을 조건으로 찾고 정렬하는 체계적인 다루기를 지원한다. 화면 안에서 상당한 양의 데이터를 보관하고 다뤄야 하는 경우에 이 수단이 쓰인다.


이 수단의 큰 특징은 데이터를 다루는 일이 흐름을 붙잡지 않게 설계되었다는 것이다. 큰 데이터를 넣고 꺼내는 동안 화면이 멈추지 않도록, 그 작업을 뒤편에서 진행하고 끝나면 결과를 알리는 방식으로 동작한다. 그래서 앞서 다룬 단순한 저장과 달리, 많은 데이터를 다뤄도 화면의 부드러움을 해치지 않는다.


이 저장은 통신망이 끊긴 상황을 대비하는 데도 쓰인다. 서버에서 받은 데이터를 이곳에 담아 두면, 나중에 연결이 없어도 그 데이터로 화면을 구성할 수 있다. 앞 편에서 언급한, 스크립트가 통제하는 자원 저장소와 짝을 이뤄, 하나는 화면을 이루는 자원을, 다른 하나는 그 화면에 채울 데이터를 맡는 식으로 오프라인 대응을 완성한다.


다만 강한 기능에는 그만한 복잡함이 따른다. 단순한 저장은 값을 넣고 꺼내는 것으로 끝나지만, 이 구조적인 저장은 데이터를 어떻게 나누어 담고 어떻게 찾을지를 미리 설계해야 한다. 그래서 담을 데이터가 작고 단순하다면 굳이 이 수단을 쓸 이유가 없다. 다루려는 데이터의 양과 구조가 이 수단을 쓸지 말지를 가르는 기준이다.

저장을 다룰 때의 함정

저장 수단을 골랐더라도 그것을 다루는 방식에 따라 성능과 안전이 갈린다. 각 수단에는 조심하지 않으면 빠지는 함정이 있고, 이를 미리 알아 두면 흔한 사고를 피할 수 있다.


첫째 함정은 용량의 한계를 잊는 것이다. 브라우저의 저장에는 담을 수 있는 양에 제한이 있고, 이를 넘기면 저장이 실패한다. 특히 저장이 실패했는데도 그것을 확인하지 않고 넘어가면, 담았다고 여긴 데이터가 실제로는 없어 나중에 엉뚱한 오류로 드러난다. 저장할 때는 그것이 성공했는지를 확인하고, 용량이 찼을 때 오래된 것을 정리하는 대비를 갖춰야 한다.


둘째 함정은 흐름을 붙잡는 저장을 큰 데이터에 쓰는 것이다. 값을 넣고 꺼내는 동안 그 순간의 흐름을 멈추는 방식의 저장에 큰 데이터를 자주 다루면, 그때마다 화면이 끊긴다. 앞서 다룬 대로 큰 데이터는 흐름을 붙잡지 않는 저장 수단으로 옮겨야 한다. 저장이 화면의 부드러움을 해치고 있지는 않은지 살펴야 한다.


셋째 함정은 민감한 데이터를 부주의하게 저장하는 것이다. 서버로 오가지 않는 저장은 편리하지만 스크립트가 자유롭게 읽을 수 있어, 여기에 로그인 표식 같은 민감한 정보를 두면 페이지에 침투한 악의적 스크립트에 그대로 노출된다. 민감한 표식은 스크립트가 읽지 못하게 막힌 수단에 두어야 하며, 편의를 위해 이 원칙을 어기면 유출의 문을 여는 셈이다.


넷째 함정은 저장한 것의 수명을 관리하지 않는 것이다. 서버로 오가지 않는 저장은 대개 스스로 만료되지 않아, 한번 담긴 것이 지워지기 전까지 계속 남는다. 그래서 더 이상 쓸모없어진 데이터가 쌓이거나, 오래되어 지금과 맞지 않는 데이터가 남아 문제를 일으킨다. 저장한 데이터에 언제까지 유효한지를 함께 담아 두고, 낡은 것을 스스로 걷어내는 정리가 필요하다.


이 함정들은 모두 저장을 담는 순간이 아니라 시간이 지난 뒤에 드러난다는 공통점이 있다. 용량은 데이터가 쌓인 뒤에 넘치고, 성능 문제는 데이터가 커진 뒤에 나타나며, 낡은 데이터는 오래 지난 뒤에 어긋난다. 그래서 저장을 다룰 때는 지금 당장의 동작뿐 아니라, 이 저장이 오래 쌓이고 낡았을 때 어떻게 될지를 함께 내다보아야 한다.


또 하나 잊기 쉬운 점은 브라우저의 저장이 영원하지 않다는 것이다. 기기의 저장 공간이 부족해지면 브라우저는 오래 쓰이지 않은 저장을 스스로 비우기도 한다. 그래서 저장해 둔 데이터가 언제나 그 자리에 있으리라 전제하고 코드를 짜면, 데이터가 사라진 상황에서 화면이 무너진다. 저장은 편의를 위한 것이지 절대적인 보관이 아니므로, 담아 둔 것이 없을 수도 있다는 전제 아래 다루어야 한다.


그래서 중요한 데이터라면 브라우저의 저장에만 의지해서는 안 된다. 브라우저의 저장은 그 기기, 그 브라우저 안에서만 유효하고 언제든 비워질 수 있으므로, 잃어서는 안 되는 데이터는 서버에 함께 보관해 두어야 한다. 브라우저의 저장은 속도와 편의를 위한 임시 자리로 여기고, 진짜 보관은 서버가 맡는 역할 분담이 안전하다.

무엇을 어디에 담을 것인가

여러 저장 수단을 앞에 두고 무엇을 어디에 담을지를 정하는 데는 몇 가지 기준이 있다. 첫째 기준은 그 데이터를 서버가 볼 필요가 있는가다. 서버가 매 요청에서 확인해야 하는 표식이라면 요청에 실려 오가는 수단에 담고, 브라우저 안에서만 쓰인다면 서버로 오가지 않는 수단에 담는다. 서버가 볼 필요 없는 데이터를 요청에 실어 보내는 것은 통신을 무겁게 하는 낭비다.


둘째 기준은 그 데이터가 얼마나 오래 살아야 하는가다. 방문이 끝나면 잊어도 되는 임시 상태는 화면을 닫으면 사라지는 수단에 두고, 다음에 다시 와도 기억해야 할 설정은 지속되는 수단에 둔다. 수명을 잘못 정하면, 잊어야 할 것이 남아 사용자를 혼란스럽게 하거나 기억해야 할 것이 사라져 불편을 준다.


셋째 기준은 그 데이터의 양과 구조다. 작고 단순한 값은 단순한 저장으로 충분하지만, 많고 복잡하게 얽힌 데이터는 체계적으로 다룰 수 있는 수단이 필요하다. 넷째 기준은 그 데이터가 얼마나 민감한가다. 로그인 표식처럼 유출되면 위험한 데이터는 스크립트가 읽지 못하게 막고 안전한 연결에서만 오가게 하는 등 엄격한 통제 아래 두어야 한다.


이 기준들을 종합하면, 저장 수단의 선택은 취향이 아니라 데이터의 성격이 정하는 문제다. 민감한 표식은 통제된 채 요청에 실리고, 단순한 설정은 가벼운 저장에 오래 남으며, 방대한 데이터는 구조적인 저장에서 뒤편으로 다뤄지고, 임시 상태는 방문이 끝나면 사라진다. 정리하면, 브라우저의 저장 수단은 서버로 오가는지, 얼마나 오래 사는지, 얼마나 크고 구조적인지, 얼마나 민감한지에 따라 나뉘며, 데이터의 성격에 맞는 수단을 고르는 것이 안전과 성능을 함께 지키는 길이다. 다음 편에서는 이 저장된 데이터를 노리는 위협을 포함해, 브라우저가 페이지들을 서로 격리해 보호하는 보안 모델을 다룬다.