HTTPS
- HTTPS(Hyper Text Transfer Protocol Secure Socket layer)
HTTP 요청을 SSL 혹은 TLS 알고리즘을 이용해 통신 과정 중 데이터를 암호화하여 전송하는 방법
1. 대칭 키와 비대칭 키
1) 대칭 키
- 양쪽이 공통의 비밀 키를 공유하여 데이터 암호화 및 복호화
- 클라이언트와 서버가 데이터를 주고받을 때 대칭키 방식 사용
2) 비대칭 키
- 각각 공개 키와 비밀 키를 가지고 상대가 나의 공개 키로 암호화한 데이터를 개인이 가진 비밀 키로 복호화
- 인증, 대칭 키를 주고받을 때 비대칭 키 방식 사용
2. 인증서
- 서버의 신원을 보증
- CA(Certificate Authority) : 인증서를 발급, 보증
- 발급 기관, 공개키 정보 등 정보 포함
1) 인증 과정
- 서버가 클라이언트에게 CA의 비밀키로 암호화된 인증서를 전달
- 클라이언트는 OS 또는 브라우저에 미리 내장되어 있던 CA 리스트를 통해 브라우저에서 인증된 CA에서 발급받은 인증서인지 확인
- 확인 되었다면 CA기관의 공개 키로 서버 인증서를 복호화
서버와 클라이언트 간의 CA를 통해 서버를 인증하는 과정과 데이터를 암호화하는 과정을 아우른 프로토콜을 TLS 또는 SSL이라고 함
(*SSL과 TLS는 사실상 동일한 규약을 뜻하며 SSL이 표준화되며 바뀐 이름이 TLS)
2) HTTPS 사설 인증서 발급 및 서버 구현해보기
mkcert 프로그램을 이용해 로컬 환경에서 신뢰할 수 있는 PKCS12 형식의 인증서 생성
(1) Spring 프로젝트 생성 및 Spring Web 라이브러리 의존성 추가
(2) 설치
$ sudo apt install libnss3-tools
$ wget -O mkcert https://github.com/FiloSottile/mkcert/releases/download/v1.4.3/mkcert-v1.4.3-linux-amd64
$ chmod +x mkcert
$ sudo cp mkcert /usr/local/bin/
- libnss3-tools:
Network Security Services(NSS) 라이브러리에 관련된 도구와 유틸리티 모음
* MacOS의 경우
$ brew install mkcert
(3) 명령어를 통해 로컬을 인증된 발급기관으로 추가
$ mkcert -install
(4) PKCS12 인증서 생성
$ mkcert -pkcs12 localhost
(5) 생성된 localhost.p12 파일을 미리 생성해둔 프로젝트의 resource 디렉토리로 이동
(6) application.yml에 관련 설정을 추가
server:
ssl:
key-store: classpath:localhost.p12
key-store-type: PKCS12
key-store-password: changeit
(7) 애플리케이션 실행하여 확인
main] o.s.b.w.embedded.tomcat.TomcatWebServer :
Tomcat initialized with port(s): 8080 (https)
3. Hashing
- 복호화가 가능한 다른 암호화 방식들과 달리, 암호화만 가능
- 해시 함수(Hash Function)를 사용하여 암호화를 진행
- 항상 같은 길이의 문자열을 리턴
- 서로 다른 문자열에 동일한 해시 함수를 사용하면 반드시 다른 결과값 리턴
- 동일한 문자열에 동일한 해시 함수를 사용하면 항상 같은 결과값 리턴
1) 레인보우 테이블과 솔트(Salt)
- 레인보우 테이블 : 항상 같은 결과값이 나온다는 특성을 이용해 해시 함수를 거치기 이전의 값을 알아낼 수 있도록 기록해 놓은 표
- 유출이 되었을 때 해싱을 했더라도 해싱 이전의 값을 알아낼 수 있으므로 보안상 위협
- 솔트 : 이전 값에 임의의 값을 더해 데이터가 유출되더라도 해싱 이전의 값을 알아내기 더욱 어렵게 만드는 방법
- 'password' = 5BAA61E4C9B93F3F0682250B6CF8331B7EE68FD8
- 'password' + 'salt' = 1D390E205862F15F174AEE7002E1CBE3B30F35C6
- 솔트를 사용하게 되면 해싱 값이 유출되더라도, 솔트가 함께 유출된 것이 아니라면 암호화 이전의 값을 알아내는 것은 불가능
2) 복호화가 불가능한 암호화 방식 사용 이유
- 해싱의 목적은 데이터 그 자체를 사용하는 것이 아니라, 동일한 값의 데이터를 사용하고 있는지 여부만 확인하는 것이 목적
- 해싱한 값끼리 비교해서 일치하는지 확인
- 정확한 값을 몰라도, 해싱한 값이 일치한다면 정확한 비밀번호를 입력했다는 뜻
4. Cookie
- 서버에서 클라이언트에 데이터를 저장하는 방법 중 하나
- 서버가 원한다면 서버는 클라이언트에서 쿠키를 이용하여 데이터 읽기 가능
- 쿠키를 이용하는 것은 단순히 서버에서 클라이언트에 쿠키를 전송하는 것뿐만 아니라 클라이언트에서 서버로 쿠키를 전송하는 것도 포함
쿠키 옵션
- 데이터를 저장한 이후 특정 조건들이 만족하는 경우에만 다시 가져올 수 있음
1) Domain
- "www.google.com" 과 같은 서버에 접속할 수 있는 이름
- 쿠키 옵션에서 도메인은 포트 및 서브 도메인 정보, 세부 경로를 포함하지 않음
- 쿠키 옵션에 도메인 정보가 존재한다면 클라이언트에서는 쿠키의 도메인 옵션과 서버의 도메인이 일치해야만 쿠키를 전송 가능
2) Path
- 세부 경로는 서버가 라우팅 할 때 사용하는 경로
- 요청 URL이 "http://www.localhost.com:3000/users/login" 일때
Path, 세부 경로는 "/users/login"
- 명시하지 않았을 시 기본값 "/"
- 설정된 path를 전부 만족하는 경우 요청하는 Path가 추가로 더 존재하더라도 쿠키를 서버에 전송 가능
- Path가 "/users" 로 설정 되어있고
요청 경로가 "/users/login" 인 경우 쿠키 전송 가능
3) MaxAge/Expires
- 쿠키의 유효기간을 설정
- MaxAge : 몇 초 동안 쿠키가 유효한지 설정
- Expires 얼마나 유효할지 date로 지정
- 지정된 시간, 날짜를 초과하게 되면 쿠키는 자동으로 파괴
- 옵션 여부에 따라 세션 쿠키와 영속성 쿠키로 구분
- 세션 쿠키(Session Cookies)
- MaxAge 또는 Expires 옵션이 없는 쿠키, 브라우저가 실행 중일 때 사용할 수 있는 임시 쿠키
- 브라우저 종료 시 쿠키 삭제
- 영속성 쿠키(Persistent Cookies)
- 브라우저 종료와 상관없이 지정된 유효시간 만큼 사용 가능한 쿠키
4) Secure
- 쿠키를 전송해야 할 때 사용하는 프로토콜에 따른 쿠키 전송 여부를 결정
- true로 설정한 경우 'HTTPS' 프로토콜을 이용하여 통신하는 경우에만 쿠키를 전송 가능
- 옵션이 없다면 프로토콜에 상관없이 쿠키 전송 가능
5) HttpOnly
- 자바스크립트에서 브라우저의 쿠키에 접근 여부를 결정
- true로 설정할 경우 자바스크립트에서 쿠키 접근이 불가능
- 명시되지 않는 경우 기본 false
- 자바스크립트에서 쿠키에 접근이 가능해 'XSS' 공격에 취약
6) SameSite
- Cross-Site 요청을 받은 경우, 요청에서 사용한 메서드(GET, POST …)와 해당 옵션의 조합을 기준으로 서버의 쿠키 전송 여부를 결정
- Cross-Site : eTLD+1이 다른 경우
- TLD(Top Level Domain) : .com, .org 같은도메인의 가장 마지막 부분
- eTLD+1 : TLD 바로 왼쪽 하위 레벨 도메인을 합한 것
.io의 경우 바로 왼쪽 주소 하나를 더한 것이 TLD
- Cross-Origin : 서버의 도메인, 프로토콜, 포트 중 하나라도 다른 경우
- 사용 가능한 속성
쿠키를 이용한 상태 유지
- 쿠키의 특성을 이용하여 서버는 클라이언트에 인증정보를 담은 쿠키를 전송하고, 클라이언트는 전달받은 쿠키를 요청과 함계 전송하여 인터넷 연결을 Stateful 하게 유지 가능
- 쿠키는 오랜 시간 동안 유지될 수 있고, 자바스크립트를 이용해서 쿠키에 접근할 수 있기 때문에 쿠키에 민감한 정보를 담는 것은 위험함
5. Session
1) 흐름
- 서버는 일종의 저장소에 세션을 저장
in-memory, 세션 스토어(redis 등과 같은 트랜잭션이 빠른 DB)에 저장
- 세션이 만들어질때 각 세션을 구분할 수 있는 세션 아이디도 만들어지며 보통 클라이언트에 세션 성공을 증명할 수단으로써 세션 아이디를 전달
- 웹사이트에서 로그인을 유지하기 위한 수단으로 쿠키를 사용하며 쿠키에는 서버에서 발급한 세션 아이디를 저장
- 쿠키를 통해 유효한 세션 아이디가 서버에 전달되고 세션 스토어에 해당 세션이 존재한다면 서버는 해당 요청에 접근 가능하다고 판단
2) 로그아웃
- 세션 아이디가 담긴 쿠키는 클라이언트에 저장되어 있으며, 서버는 세션을 저장하고 있고 서버는 세션 아이디로만 인증 여부를 판단
- 쿠키는 세션 아이디, 즉 인증 성공에 대해 증명을 하고 있으므로, 탈취될 때 서버는 해당 요청이 인증된 사용자의 요청이라고 판단
- 로그아웃 시 서버는 세션 정보를 삭제, 클라이언트는 쿠키를 갱신
- 서버가 클라이언트의 쿠키를 임의로 삭제는 불가능하며 set-cookie로 클라이언트에게 쿠키를 전송할 때 세션 아이디의 키 값을 무효한 값으로 갱신 가능
6. 보안 공격
1) SQL Injection
- 데이터베이스에서 임의의 SQL 문을 실행할 수 있도록 명령어를 삽입하여 공격
- 데이터베이스를 비정상적으로 조작
- 사용자가 input form에 직접 무언가 작성하는 상황에서 발생
로그인시 예시 코드
SELECT *
FROM users
WHERE auth='admin'
AND id='jungseo';
공격시 예시 코드
SELECT *
FROM users
WHERE auth='admin'
AND id='' OR '1'='1';
- WHERE 절에서 OR는 AND보다 연산 순위가 낮으므로 OR 절인 ‘1’ = ‘1’ (항상 참)이 가장 나중에 실행되어 결국 로그인에 성공
대응 방안
-
입력(요청) 값 검증
- 화이트리스트 방식으로 해당 키워드가 들어오면 다른 값으로 치환하여 SQL Injection에 대응
- 화이트리스트란 기본 정책이 모두 차단인 상황에서 예외적으로 접근이 가능한 대상을 지정하는 방식 또는 그 지정된 대상
-
Prepared Statement 구문 사용
- 사용자의 입력이 SQL 문으로부터 분리
- 사용자의 입력값이 전달되기 전에 데이터베이스가 미리 컴파일하여 SQL을 바로 실행하지 않고 대기
- 사용자의 입력값을 단순 텍스트로 인식
- 입력값이 SQL 문이 아닌 단순 텍스트로 적용되며 공격에 실패
-
Error Message 노출 금지
- Error Message를 통해 테이블 컬럼 등 정보를 얻을 수 있어 발생 SQL문과 에러 내용이 노출 되지 않도록 에러 핸들링 필요
2) CSRF(Cross-Site Request Forgery)
- 사이트 간 요청 위조
- 사용자가 자신의 의지와는 무관하게 공격자가 의도한 행위(수정, 삭제, 등록 등)를 특정 웹사이트에 요청
- 사이트간 요청 위조는 특정 웹사이트가 사용자의 웹 브라우저를 신용하는 상태를 노림
- 사용자가 웹사이트에 로그인한 상태에서 사이트간 요청 위조 공격 코드가 삽입된 페이지를 열면, 공격 대상이 되는 웹사이트는 위조된 공격 명령이 믿을 수 있는 사용자로부터 발송된 것으로 판단하게 되어 공격에 노출
과정
- 이용자는 웹사이트에 로그인하여 정상적인 쿠키를 발급
- 공격자는 도착지를 변조한 이미지 태그를 가진 HTML 페이지 링크를 이메일이나 게시판 등의 경로를 통해 이용자에게 전달
- 이용자가 공격용 페이지를 열면, 브라우저는 이미지 파일을 받아오기 위해 공격용 URL 엶
- 이용자의 승인이나 인지 없이 출발지와 도착지가 등록됨으로써 공격이 완료
대응 방안
- CSRF 토큰 사용
- 웹 애플리케이션에서는 사용자의 세션과 관련된 CSRF 토큰을 생성하고 이를 웹 요청에 포함
- 서버는 요청을 처리하기 전에 CSRF 토큰을 확인하여 유효성을 검증
- SameSite 쿠키 속성 설정
- 속성을 "Strict"로 설정하면, 같은 사이트에서만 쿠키가 전송되고 외부 도메인으로의 요청에서는 쿠키가 포함되지 않음
3) XSS(Cross-Site Scrption)
- 사이트 간 스크립팅
- 웹사이트 관리자가 아닌 이가 웹 페이지에 악성 스크립트를 삽입
- 사용자의 정보(쿠키, 세션 등)를 탈취하거나, 자동으로 비정상적인 기능을 수행 가능
- 주로 다른 웹사이트와 정보를 교환하는 식으로 작동
과정
- 웹 애플리케이션의 입력 폼, 코멘트 기능, 사용자 입력을 표시하는 부분 등을 통해 악성 스크립트를 삽입
- 악성 스크립트는 사용자가 웹 애플리케이션을 요청할 때 서버에서 클라이언트(웹 브라우저)로 전달
스크립트는 주로 웹 페이지의 일부로서 실행될 수 있도록 HTML 태그나 이벤트 핸들러에 삽입
- 웹 브라우저는 악성 스크립트를 받고, 스크립트를 실행
- 스크립트는 웹 페이지의 콘텍스트 내에서 실행되어 사용자의 권한으로 웹 페이지를 조작하거나, 다른 웹 사이트로 사용자의 정보를 전송하는 등의 악의적인 행위를 수행 가능
대응 방안
- 입력 검증
- 사용자 입력 데이터를 신뢰할 수 있는 형식으로 변환 또는 제한
- 입력 필드에서 예상되는 데이터 형식을 확인하고, 허용되지 않은 문자나 코드를 필터링
- 입력 데이터를 검증하는 서버 측 및 클라이언트 측의 유효성 검사를 수행
- 출력 이스케이프
- 웹 애플리케이션이 사용자 입력을 표시할 때는, 특수 문자를 이스케이프하여 사용자 입력이 스크립트로 인식되지 않도록 처리
- HTML, JavaScript, CSS 등의 웹 기술을 사용하는 출력에 대해 이스케이프 처리를 적용
- 이스케이프 함수 또는 라이브러리를 사용하여 적절한 형태로 출력을 변환