코코야이야기
[시큐어코딩] 쿠키 및 세션관리 본문
[시큐어코딩] 쿠키 및 세션관리
1. 쿠키 (Cookie)
- Statless 프로토콜인 HTTP 통신 시 서버가 사용자 정보를 유지하기위해 생성해서 응답 헤더에 붙여 클라이언트에게 전송하는 정보
- 쿠키 정보는 사용자 PC의 메모리 또는 파일에 저장되고, 해당 사이트에 요청을 전송할 때 이름=값 형식으로 효청 헤더에 포함되어 서버에 전달됨
* 제약사항
- 브라우저당 최대 300개 각 호스트마다 최대 20개까지 사용가능
- 크기는 최대 4KB까지 가능(브라우저마다 다름)
* 용도
- 세션 관리를 위한 세션 토큰 저장
- 클라이언트 관리에 필요한 정보, 팝업창 제한 설정과 같은 임시데이터 관리
- 제공 정보의 커스터마이징을 위한 사용자 취향 등 저장
세션쿠키 (Session Cookie) | 영구쿠기 (Persistent Cookie) |
- 브라우저가 열려 있는 동안 유효함 | - 하드디스크에 유효기간 동안 저장됨 |
- 서버를 이용하는 동안 사용자 정보를 유지하기 위해 사용됨 | - 사이트 재방문 시 사용자 정보를 기억하기 위해 사용됨 |
* 쿠키 사용에 대한 법률적인 제한
쿠키의 사용을 직접적으로 금지하거나 제한하는 법률은 존재하지 않으나 여러 방법으로 침해로부터 보호하고 있음
"쿠키를 운용하는 웹서버는 개인정보보호정책의 일환으로서 쿠키의 존재, 쿠키로 수집하는 정보의 형태와 내용, 수집의 방법과 수집한 개인정보의 사용 목적을 분명하고 정확하게, 가능한 한 인터넷이용자가 이해하기 쉽게 공개하여야 한다."
- 개인정보보호지침 제7조 1항 2호 참조 -
* 서버에서 쿠키를 생성하여 전송하는 코드 순서
응답 메시지의 Set-Cookie: 라는 헤더값으로 클라이언트에 전달됨
1) 쿠키 객체 생성
2) 쿠키 속성 설정
3) 쿠키 전송
Cookie cookie = new Cookie("username", "kim");
cookie.setMaxAge(60*60*24*7)
response.addCookie(cookie);
* 클라이언트에서 서버로 쿠키 전송
브라우저에서 Cookie 객체에 저장된 값을 사이트별로 읽어서 전송함
1) 쿠키정보 얻기
2) 쿠키에 설정되어있는 정보보기
Cookie[] cookies = request.getCookies();
for(int i=0;i<cookies.length;i++){
String name = cookies[i].getName();
if(name.equals("username")){
String username = cookies[i].getValue();
}
}
* 쿠키 보안 취약점
- XSS(크로스 사이트 스크립트)공격
˙ 자바스크립트를 이용하여 document.cookie 값을 탈취할 수 있음
- 스니핑(Sniffing)공격을 이용
˙ 네트워크를 통해 전송되는 쿠키값을 암호화하지 않고 전송하는 경우 네트워크 스니핑 공격을 통해 쿠키값을 탈취할 수 있음
- 공용 PC에서 쿠키값 유출
˙ 영속성 쿠키는 하드디스크에 저장되며, 간단한 방법으로 접근 가능하기 때문에 공용PC 사용시 PC에 저장된 사용자 정보가 유출될 수 있음
* 쿠키의 속성
- Domain : 브라우저가 쿠키값을 전송할 서버의 도메인 지정
cookie.setDomain("coyagi.tistory.com");
- Path : 브라우저가 쿠키값을 전송할 URL 지정
cookie.setPath("/user");
- Expires : 쿠키의 유효기간 설정
cookie.setMaxAge(24*60*60);
- Secure : SSL 통신채널 연결 시에만 쿠키를 전송하도록 설정
cookie.setSecure(true);
- HttpOnly : 자바 스크립트에서 쿠키값을 읽어가지 못하도록 설정
cookie.setHttpOnly(true);
2. 세션
- 상태관리를 하지 않는 HTTP에서 클라이언트의 정보를 관리하기 위한 논리적인 연결
˙ 서버는 클라이언트의 정보를 유지하기 위해 세션 메모리를 할당해 클라이언트의 인증정보를 관리함
˙ 할당된 세션 메모리를 클라이언트별로 구분하기 위해 세션 ID를 할당하고, 클라이언트가 지속적으로 세션 ID를 서버로 전달할 수 있도록 쿠키나 URL파라미터, <form>의 hidden 파라미터 값으로 전달하게 함
˙ 관리되지 않는 경우, 다른 사용자의 권한으로 해당 시스템의 서비스를 사용할 수 있는 세션 하이재킹 공격이 이루어질 수 있음
세션 ID 추측 | 세션 ID 훔치기 | 세션 ID 고정 |
- 세션 ID 생성 방법이 부적절한 경우 제3자가 추측 가능하여 세션 하이재킹이 가능함 | - 네트워크상에서 패킷 스니핑을 통한 세션 ID 약탈 | - 공격자가 사용자의 브라우저에 세션 ID를 설정하는 것이 가능하다면, 공격자는 이미 사용자의 세션 ID를 알고 있는 상태가 될 수 있으므로 세션 하이재킹이 가능하게 됨 |
- XSS(크로스 사이트 스크립트)등 애플리케이션 취약점에 의한 유출 | ||
- URL에 가지고 있는 Redirect를 이용하거나, 브라우저의 취약점을 통해 세션 ID 약탈 |
* 세션관리 5가지 진단
1) 진단 1
"세션 ID 추측이 가능한가?"
- 사이트에 시간대별로 여러번 접속하여 할당되는 세션 ID가 추측이 가능한지 확인함
- 수동으로 진행하기 어렵기 때문에 툴을 사용해 테스트할 수 있음
(오픈소스 프록시 툴인 WebScarab의 SessionID Analysis Plugin)
1] 대응기법 #1
세션 ID를 공격자가 추측하기 어렵게 길고 랜덤하게 생성하는 알고리즘을 사용함
- 추측이 불가능한 세션 ID를 발생할 수 있는 안전한 알고리즘을 사용함
- 세션 ID 생성 범위 값을 사용자 수에 대비하여 충분히 큰 값으로 설정함
- 일반적으로 웹서버에서 할당하는 세션 ID를 사용하는 것을 권장함
2) 진단 2
"쿠키값을 조작해 세션 훔치기가 가능한가?"
- 사이트 접속 후 cooxie툴을 이용해 현재 세션 값을 편집해서 세션 훔치기가 가능한지 확인함
- 로그인한 세션 ID 정보를 패킷 스니핑이나 XSS 취약한 사이트를 이용해 획득한 뒤, 해당 세션 ID 정보를 이용해 세션 훔치기를 시도해 봄
- 웹서버가 클라이언트의 인증정보를 세션 ID에 저장된 사용자 정보만으로 확인하는 로직을 가지고 있다면 공격자는 세션 ID 조작을 통해서 손쉽게 HTTP 세션 하이재킹을 성공할 수 있음
2] 대응기법 #2
세션 ID가 포함된 세션 쿠키가 안전하게 송수신되도록 설정함
- 자바 스크립트에서 세션 ID 정보를 읽을 수 없도록 세션 쿠키에 httponly 속성을 true 로 설정함
- 패킷 스니핑을 통해 세션 ID 정보가 노출되지 않도록 암호화된 채널을 통해 전송하도록 세션 쿠키에 secure 속성을 true 로 설정함
ex1) Tomcat 5.5.258 이후 버전 conf/context.xml에서 설정
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/secure" useHttpOnly="true">
ex2) servlet 3.0이 지원되는 경우 web.xml 파일에서 설정
<session-config>
<cookie-config>
<http-only>true</http-only>
<secure>true</secure>
</cookie-config>
</session-config>
ex3) JEUS 6.0 fix9 버전부터는 http-only가 default로 true로 설정
˙ WEBMain.xml이나 jeus-web-dd.xml에 명시적으로 설정도 가능
<session-config>
<session-cookie>
<jsessionid-name>JSESSIONID</jsessionid-name>
<version>0</version>
<domain>.tmax.co.kr</domain>
<path>/</path>
<max-age>-1</max-age>
<secure>false</secure>
<http-only>true</http-only>
</session-cookie>
</session-config>
ex4) JBOSS 5.0.1과 JBOSS EAP 5.0.1 /server/<jboss서버인스턴스/deploy/jbossweb.sar/context.xml에서 설정
<Context cookies="true" crossContext="true">
<SessionCookie secure="true" httpOnly="true" />
3) 진단 3
"세션 ID 고정 공격이 가능한가?"
(1) 진단하고자 하는 사이트에 A 브라우저로 접속하여 얻은 세션 ID 를 사용하여 로그인을 요청할 수 있도록 요청 URL을 조립
(2) B 브라우저를 이용하여 해당 URL을 클릭, 로그인을 수행함
(3) B 브라우저가 로그인 된 세션 ID 와 A 브라우저의 세션 ID 가 동일지 확인함
3] 대응기법 #3
조작하여 요청 보낼 수 없도록 URL rewrite 기능을 사용하지 않고, 록인 성공 시 세션 ID 를 재할당함
- URL rewrite와 같은 기능을 구현하지 않음
- URL rewrite로 이동되는 페이지는 세션 ID 정보가 URL에 포함되므로 공격자들이 쉽게 세션 ID 고정 공격을 수행할 수 있어 로그인 성공 시 세션 ID를 재할당 하도록 프로그램을 작성함
if(loginSuccess){
session.invalidate();
session=request.getSession();
session.setAttribute("user", user);
}
4) 진단 4
"자동 로그아웃 기능이 있는가?"
- 세션 타임아웃이 적절하게 수행되지 않은 경우, 사용자가 자리를 비운 사이 악의적인 사용자가 해당 웹 브라우저를 이용하여 로그인한 사용자의 계정 정보를 이용하여 임의의 작업을 수행할 수 있음
4] 대응기법 #4
서버 환경설정을 통해 자동 로그아웃 기능을 설정함
<session-config>
<session-timeout>300</session-timeout>
</session-config>
5) 진단 5
"로그아웃 후 다시 브라우저로 페이지에 접속할 경우 세션이 종료되어 있는가?"
- 로그아웃을 수행할 때 세션을 완전히 삭제하고 로그아웃을 수행하는지 확인
- 로그아웃을 수행하고 브라우저를 종료하지 않는 경우 세션 ID가 지속적으로 사용되어 이전 사용자 정보가 삭제되지 않고 유효한지 확인
5] 대응기법 #5
로그아웃 요청 처리 시 세션 정보를 완전히 삭제함
@RequestMapping("/logout.do")
public String logout(HttpSession session){
session.invalidate();
return "redirect:login.do";
}
* 헤더값 활용
(1) XSS 공격을 방어하기 위한 Content-Security-Policy
(2) 클릭재킹을 방어할 수 있는 X-Frame-Options
(3) 파일의 마임타입을 정확하게 확인할 수 있는 X-Content-Type-Options
(4) SSL Strip 공격을 방어하기 위한 Strict-Transport-Security
* Content-Security-Policy
- XSS 공격 예방을 위해 Content-Security-Policy 헤더를 설정할 수 잇음
- 누군가 페이지에 외부 스크립트 등을 걸어서 XSS 공격을 할 수 있기 때문에 페이지에서 허용할 origin을 script-src로 지정할 수 있음
script-scr:JavaScript code
connect-src:XMLHttpRequest, WebSockets, and EventSources.
font-src:fonts
frame-src:frame ulrs
img-src:images
media-src:audio&video
object-src:Flash(and other plugins)
style-src:CSS
Content-Security-Policy:script-src 'self' https://apis.google.com
· 자신의 사이트와 구글의 각종 스크립트들만 허용함
- 응답 메시지의 헤더값 설정 방법
: 프로그램(일반적으로 Controller 컴포넌트)에서, response 헤더값은 setHeader() 메서드를 사용해 설정
response.setHeader("Content-Security-Policy", "script-src 'self' https://apis.google.com");
* 클릭재킹(ClickJacking)
- <iframe> 태그를 이용한 눈속임으로, 희생자는 A페이지의 버튼을 클릭하지만 실제로는 B페이지 컨텐츠를 클릭하게 하는 공격을 말함
* X-Frame-Options
- ClickJacking과 같은 공격을 무력화 하기 위해 X-Frame-Options를 설정하여 사용
- X-Frame-Options:DENY (프레임 안에 절대 들어가지 못하게 한다)
- X-Frame-Options:SAMEORIGIN (같은 origin 일 경우에만 허용한다)
- X-Frame-Options:ALLOW FROM http://aaa.com (특정 origin에서만 허용한다)
X-Frame-Options:deny
* X-Content-Type-Options
- script나 stylesheet 요소는 서버가 X-Content-Type-Options : nosniff 응답 헤더를 보내는 경우 잘못된 MIME 형식이 포함된 응답을 거부함
- 예 : stylesheet는 MIME 형식이 text/css인 경우에만 파일을 로드함
- script는 MIME 형식이 아래와 같을 때만 파일을 로드함
˙ "application/ecmascript"
˙ "application/javascript"
˙ "application/x-javascript"
˙ "text/ecmascript"
˙ "text/javascript"
˙ "text/jscript"
˙ "text/x-javascript"
˙ "text/vbs"
˙ "text/vbscript"
X-Content-Type-Options: nosniff
* Strict-Transport-Security
- 보안 연결이 지정된 사이트만 접근 가능하도록 강제할 수 있어, 일반적인 URL로 접근할 때도 강제로 HTTPS로 접속하게 만듦
- 이 헤더 설정을 통해 main-in-middle 공격을 예방할 수 있음
Strict-Transport-Security: max-age=16070440; includeSubDomains
Q : 타 도메인간 쿠키를 공유하는 방법
A :
(1) 프로그램단에서 헤더 파일을 이용하는 방법
- 서로 다른 도메인을 포함하는 프레임 구조에서 쿠키 정보 남용을 막기 위해 W3C에서는 P3P(Platform for Personal Preferences)규약을 정의하고 있음
- 이 규약을 해결하기 위해서는 쿠키를 적용하는 웹페이지에서 p3p 규약을 허용하는 HTTP 헤더를 추가하거나, 쿠키를 적용하는 웹서버에서 p3p 규약을 허용하는 HTTP 헤더를 추가
<head>
<meta http-equiv="p3p" content='CP="CAO DSP AND SO" policyref="/w3c/p3p.xml"'>
</head>
(2) DB를 이용하는 방법
- DB 세션을 사용하면 A 도메인에서 B 도메인으로 넘어갈 때 세션 ID만 넘겨주면 쉽게 처리가능
(3) SSO(Single-Sign-On) 서버를 이용한 별도의 인증절차를 거치는 방법
* 총정리
쿠키관리
- 쿠키는 서버에서 필요로하는 클라이언트 정보를 클라이언트가 서버에 요청을 보낼 때 자동적으로 헤더에 붙여서 전달하도록 하는 매커니즘의 구현체임
- 하드디스크에 저장되는 영속성 쿠키는 중요 정보를 가지지 않도록 관리해야 하며, 세션 쿠키는 자바 스크립트에서 액세스할 수 없도록 쿠키의 속성을 설정해서 사용해야 함
- 중요 정보를 가지고 있는 쿠키는 반드시 암호화된 데이터 통신에서만 전달되도록 해야 함
세션관리
- 세션은 웹서버와 브라우저 사이의 논리적인 연결이며, HTTP 프로토콜은 상태를 관리하지 않는 (Stateless) 프로토콜임
- 하나의 연결에 하나의 요청을 처리하고 나면 연결이 종료됨
- 지속적인 연결을 관리하기 위해 서버는 클라이언트당 세션 메모리를 할당하고 해당 메모리는 세션 ID로 구분함
- 여기서 사용되는 세션 ID가 외부로 유출되면 다른 사용자의 세션을 도용해서 사용 가능한 취약점이 발생하기 때문에 세션관리에 세심한 주의가 요구됨
유용한 HTTP 헤더 설정을 통한 보안 강화
- 서버의 응답 헤더에 서버의 보안 정책을 헤더값으로 설정하는 것이 가능함
- 헤더 설정을 통해 XSS, 클릭재킹, 스니핑 등 다양한 취약점들 제거 또는 완화시킬 수 있음
'프로그래밍 > 보안' 카테고리의 다른 글
사용자 식별 방법 - 세션 (0) | 2023.04.03 |
---|---|
[시큐어코딩] 취약한 난수생성 - Math.random() (0) | 2023.03.31 |
[시큐어코딩] 접근제어 (1) | 2019.07.01 |
[시큐어코딩] 계정 및 인증관리 (0) | 2019.06.18 |