소프트웨어 개발보안 가이드 분석(2021) : 사용자 하드디스크에 저장되는 쿠키를 통한 정보노출
대부분의 웹 응용프로그램에서 쿠키는 메모리에 상주하며, 브라우저의 실행이 종료되면 사라진다.
프로그래머가 원하는 경우, 브라우저 세션에 관계없이 지속적으로 저장되도록 설정할 수 있으며, 이것은 디스크에 기록되고,
다음 브라우저 세션이 시작되었을 때 메모리에 로드된다.
개인정보, 인증 정보 등이 이와 같은 영속적인 쿠키에 저장된다면, 공격자는 쿠키에 접근할 수 있는 보다 많은 기회를 가지게 되며,
이는 시스템을 취약하게 만든다.
소프트웨어 개발보안가이드(2021), 한국인터넷진흥원
인터넷 이용이 증가함에 따라 웹사이트에서는 사용자 경험을 향상시키고 개인화된 서비스를 제공하기 위해 다양한 방법을 사용합니다. 그 중 하나가 쿠키입니다. 쿠키는 사용자가 웹사이트를 방문할 때 생성되어 사용자의 컴퓨터에 저장되는 작은 데이터 파일입니다. 하지만 이러한 쿠키를 통해 개인정보가 노출되고 사용자의 프라이버시가 침해될 수 있습니다.
이번 포스팅에서는 사용자 하드디스크에 저장되는 쿠키를 통한 정보노출에 대한 취약한 코드 예제와 이를 방지하기 위한 안전한 코드 작성 방법을 살펴보려고 합니다.
사용자 하드디스크에 저장되는 쿠키를 통한 정보노출이란?
일반적으로 웹사이트는 쿠키를 사용하여 사용자의 선호도나 로그인 정보 등을 저장하여 다음 재방문시에 사용자를 식별하고 개인화된 경험을 제공합니다. 그러나 이러한 쿠키는 사용자의 하드디스크에 저장되기 때문에 공격자의 접근에 의해 탈취되어 정보노출로 이어지는 취약점 입니다.
공격 메커니즘
쿠키 만료 날짜가 설정되지 않거나 유효 기간이 너무 길게 설정된 경우에 공격자는 쿠키를 훔쳐 사용자의 세션을 탈취하거나 변조할 수 있습니다.
공격자는 사용자 하드디스크에 저장된 쿠키를 탈취하면, 영속적인 쿠키의 경우 장기간에 걸쳐 사용자의 계정을 위조할 수 있습니다.
결과적으로 사용자가 웹사이트에 로그인할 때 생성되는 세션 쿠키는 사용자를 식별하는 데 사용되기 때문에 쿠키가 유출되면 해커가 해당 계정에 무단으로 접근하여 웹 사이트에 액세스하여 사용자 대신 악의적인 작업을 수행할 수 있습니다.
취약한 웹 애플리케이션의 예
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
1 String username = request.getParameter("username");
1 String password = request.getParameter("password");
2 if (username.equals("admin") && password.equals("password")) {
3 Cookie sessionCookie = new Cookie("sessionId", "ABC123");
4 response.addCookie(sessionCookie);
5 response.sendRedirect("/dashboard.jsp");
} else {
// 인증 실패 시
}
}
}
- 1 : 사용자가 입력한 username과 password를 가져옵니다.
- 2 : 사용자가 입력한 username과 password가 admin과 password가 사용자 인증을 합니다.
- 3 : 사용자 인증이 성공한 경우, 세션 ID가 ABC123인 세션 쿠키를 생성합니다. 다만, 세션 쿠키의 만료 날짜가 설정되지 않았습니다.
- 4, 5 : 세션 쿠키를 응답에 추가하여 사용자에게 보여줄 페이지를 리다이렉션 합니다.
- 쿠키의 만료 날짜가 설정되지 않아 브라우저가 종료될 때까지 해당 쿠키가 유지됩니다. 공격자가 사용자의 컴퓨터에 접근하여 해당 쿠키를 훔치면 사용자의 계정으로 로그인할 수 있습니다. 이를 통해 공격자는 사용자를 위장하여 권한이 있는 기능을 실행하거나 개인 정보에 접근할 수 있기 때문에 쿠키의 만료 날짜를 설정하거나 만료기간을 과도하게 길게 설정하지 않아야 합니다.
※ 해당 코드는 쿠키의 만료 날짜가 설정되지 않았음을 보여주기 위하여 다른 취약점 요소들은 배제하고 작성되었습니다.
시큐어코딩 적용 방법
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
if (username.equals("admin") && password.equals("password")) {
1 String sessionId = generateSessionId();
2 Cookie sessionCookie = new Cookie("sessionId", sessionId);
3 sessionCookie.setMaxAge(60 * 30); // 만료 시간 설정 (예: 30분)
response.addCookie(sessionCookie);
response.sendRedirect("/dashboard.jsp");
} else { /* 인증 실패 시 */ };
}
private String generateSessionId() {
4 return UUID.randomUUID().toString(); // UUID를 사용하여 랜덤한 문자열로 세션 ID 생성
}
}
- 1 : 사용자 인증 성공 시 generateSessionId 메서드를 통해 랜덤한 문자열로 세션 ID를 받아옵니다.
- 2 : 받아온 세션 ID를 쿠키에 추가합니다.
- 3 : 쿠키의 만료 시간을 설정합니다.(초 단위로 설정되어 1800초=30분 설정)
- 4 : 세션 ID 생성은 추측하기 어려운 랜덤한 값으로 생성해야합니다.(해당 코드는 랜덤한 문자열을 생성하는 방법으로 비교적 간단하고 편리하지만 보안에 있어선 적합하지 않음)
- 결과적으로 쿠키의 보안을 강화하기 위해 만료 날짜를 적절히 설정하였습니다. 만료 시간 설정은 정해져 있는 것이 없습니다. 각각의 소프트웨어 상황에 맞게 적절히 사용해야 합니다. 또한 쿠키의 보안 강화를 위해 Secure 옵션, HttpOnly 옵션 또한 사용해 주는 것이 좋습니다.
사용자 하드디스크에 저장되는 쿠키를 통한 정보노출을 방지하기 위한 보안 대책은 다음과 같은 방법들이 있습니다.
- 쿠키의 만료 날짜 설정 : 모든 쿠키에는 적절한 만료 날짜를 설정해야 합니다. 민감한 작업을 수행하는 경우에는 세션 기반의 쿠키를 사용하여 세션이 종료되면 즉시 쿠키를 만료시켜 재사용을 방지해야 합니다.
- HTTPS 사용 : 쿠키를 전송할 때 HTTPS를 사용하여 데이터의 암호화를 보장하고 중간자 공격을 방지해야 합니다. HTTPS를 사용하지 않으면 공격자가 네트워크에서 쿠키를 가로채어 변조할 수 있습니다.
- 쿠키의 보안 옵션 설정 : 보안 플래그인 HttpOnly와 Secure를 설정하여 쿠키의 안전성을 강화해야 합니다. HttpOnly 플래그를 설정하면 JavaScript에서 쿠키에 접근하는 것을 방지하고, Secure 플래그를 설정하면 HTTPS 연결에서만 쿠키가 전송되도록 합니다.
- 감시 및 로깅 : 웹 애플리케이션에서 쿠키를 사용하는 부분을 지속적으로 감시하고 로깅하여 쿠키의 부적절한 사용을 탐지하고 조치할 수 있도록 합니다.
- 정기적인 쿠키 관리 : 사용자가 로그아웃하거나 세션이 종료된 후에는 쿠키를 즉시 만료시키는 등의 정기적인 쿠키 관리를 수행하여 보안을 유지해야 합니다.