HTTPS 사용 계기
프로젝트에 구글 로그인 기능을 도입하기로 결정했으나, 배포 환경에서 구글 로그인을 시도하던 중 '400 오류: redirect_uri_mismatch' 가 발생했다. 문제의 원인은 구글 OAuth 2.0 정책을 준수하지 않았기 때문이었는데, 구글 정책에 따르면 OAuth 2.0 엔드포인트인 https://accounts.google.com/o/oauth2/v2/auth 에는HTTPS 프로토콜을 통해서만 접근할 수 있다. 사용자 데이터 보호와 안전한 인증을 위해 구글이 HTTP 연결을 허용하지 않았기 때문이다.
그러나 우리 프로젝트는 구글 로그인 창을 배포된 창에 띄우고 싶었고 따라서 HTTPS를 프로젝트에 적용하기로 결정했다.
(결과적으론 성공하지 못해 다른 방법을 사용해 구글 로그인을 구현했다. 해당 방법은 이후 포스팅으로 업데이트 할 예정이다.)
HTTPS
HTTPS를 설명하기 전에, HTTP를 알면 이해가 쉽다.
HTTP란?
HTTP(HyperText Transfer Protocol)는 말 그대로 웹 상에서 정보를 교환하기 위한 프로토콜이다. 클라이언트(웹 브라우저)와 서버 간의 통신을 가능하게 한다.
HTTP 요청은 일반적으로 '메서드 URL 프로토콜/버전', 요청 헤더, 그리고 요청 본문으로 구성된다.
GET /index.html HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
- GET: 사용되는 HTTP 메서드, 이 예에서는 서버에 /index.html의 내용을 요청한다.
- /index.html: 요청하는 리소스의 경로
- HTTP/1.1: 사용하는 HTTP 프로토콜의 버전
- Host: 요청이 전송되는 대상 웹 서버의 도메인 이름
- User-Agent: 요청을 보내는 클라이언트의 정보
- Accept: 클라이언트가 처리할 수 있는 MIME 타입을 지정
HTTP 응답은 '프로토콜/버전 상태코드 상태메시지', 응답 헤더, 그리고 응답 본문으로 구성된다.
HTTP/1.1 200 OK
Date: Mon, 23 May 2022 22:38:34 GMT
Server: Apache/2.4.1 (Unix)
Content-Type: text/html; charset=UTF-8
Content-Length: 138
Last-Modified: Sat, 20 May 2022 18:25:44 GMT
<html>
<head>
<title>An Example Page</title>
</head>
<body>
Hello World, this is a very simple HTML document.
</body>
</html>
- HTTP/1.1: 응답에 사용된 HTTP 프로토콜의 버전
- 200 OK: 상태 코드와 메시지로, 요청이 성공적으로 처리되었음을 나타낸다.
- Date: 응답이 생성된 날짜와 시간
- Server: 응답을 보내는 서버의 정보
- Content-Type: 응답 본문의 MIME 타입을 지정
- Content-Length: 응답 본문의 길이(바이트 단위)
HTTP 요청은 암호화되지 않은 텍스트로 데이터를 전송하기 때문에 제 3자의 도청, 데이터 변조, 메시지 위조 등의 보안 취약점을 가진다.
HTTPS란?
HTTPS(HyperText Transfer Protocol Secure)는 간단히 HTTP+암호화이다. 즉, HTTP에 데이터 암호화를 추가한 보안 프로토콜이다. SSL(Secure Sockets Layer)또는 TLS(Transport Layer Security) 프로토콜을 사용하여 데이터를 암호화한다.
데이터 암호화로 제 3자에 의해 데이터가 변조될 위험이 낮아져 데이터 무결성을 보장할 수 있다. 그러나 암호화/복호화 과정에서 약간의 성능 저하가 발생할 순 있지만, 최신 기술과 하드웨어의 발전으로 이러한 단점은 크게 줄어들었다.
HTTPS의 핵심 원리는 다음과 같다.
1. 암호화
- 대칭 암호화: 데이터를 암호화하고 해독하는 데 동일한 키를 사용한다. 통신하는 양쪽 모두가 같은 키를 공유하여 데이터를 암호화하고 복호화한다.
- 비대칭 암호화: 데이터를 암호화하는 데는 공개 키를, 해독하는 데는 비밀 키를 사용한다. 키 교환 문제를 해결하여 안전한 통신을 가능하게 한다.
❓왜 HTTPS에선 대칭/비대칭 암호화를 모두 사용할까
보안성을 극대화하면서도 통신 효율성을 유지하기 위함이다. 각 암호화 방식은 각각의 장단점이 있고, HTTPS는 이를 조합하여 강력한 보안을 제공한다.
[비대칭 암호화 사용 시점]
HTTPS 연결 초기에 SSL/TLS 핸드셰이크 과정에서 비대칭 암호화가 사용된다. 이 단계에서 클라이언트와 서버는 서로를 인증하고 통신에 사용할 대칭 키를 안전하게 교환한다. 비대칭 암호화의 주된 목적은 안전한 키 교환과 서버 인증에 있다.
[대칭 암호화 사용 시점]
대칭 키가 안전하게 교환되고 나면, 나머지 세션 동안의 데이터 전송에는 대칭 암호화가 사용된다. 대칭 암호화는 비대칭 암호화에 비해 계산이 훨씬 더 빠르고 효율적이기 때문에, 실제 데이터 전송에 적합하다.
만약 대칭 암호화만 사용한다면, 키 교환 문제가 발생하는데 이는 안전한 채널이 없는 상태에서 통신 양측이 비밀 키를 안전하게 공유하기 어렵다는 문제가 있다. 대칭 암호화에서는 양쪽 모두 같은 키를 사용해야 하기 때문에, 이 키를 어떻게 안전하게 교환할지가 큰 문제이다.
HTTPS에서는 이 문제를 비대칭 암호화를 사용하여 해결한다. 초기 핸드셰이크 과정에서 서버는 자신의 공개 키를 클라이언트에게 제공하고 클라이언트는 이 공개 키로 세션 키(대칭 키)를 암호화하여 서버에 전송하고, 서버는 자신의 비밀 키로 이를 해독한다. 이후 통신은 이 대칭 키로 암호화하여 진행한다.
2. 데이터 무결성
데이터가 전송 과정에서 손상되거나 변경되지 않았음을 보장한다. 이는 해시 알고리즘을 통해 확인할 수 있다.
🤯 해시 알고리즘(Hash algorithm)을 왜 사용할까
Hash는 key-value 쌍으로 데이터를 저장하는 자료구조이다. 해시 알고리즘은 어떤 입력 값에 대해 고정된 길이의 해시 값을 출력하는 함수이다. 즉, 입력 값이 조금이라도 변경되면 해시 값도 크게 달라진다. 따라서 이러한 특성을 이용하여 데이터의 무결성을 검증할 수 있다.
3. 인증
서버와 클라이언트 간의 안전한 연결을 위해 SSL 또는 TLS 프로토콜을 사용하여 통신을 암호화하고 인증한다.
- SSL란 Secure Sockets Layer의 약자로 암호화 기반 인터넷 보안 프로토콜이다. 전달되는 모든 데이터를 암호화하고 특정한 유형의 사이버 공격도 차단한다. SSL은 TLS암호화의 전신이기도 하다. SSL은 1996년 SSL 3.0 이후 업데이트 되지 않았으며, 앞으로 사라지게 될 것으로 여겨진다. 보안 전문가들은 SSL 사용 중단을 권장한다고 한다. 그 대안으로는 TLS가 있다.
- TLS란 Transport Layer Security의 약자로 SSL의 업데이트 버전이다. SSL 3.0 버전과 TLS 최초버전의 차이는 크지 않으며, 이름이 바뀐 것은 SSL을 개발한 Netscape가 업데이트에 참여하지 않게 되어 단순 소유권 변경을 위해서였다고 한다. 결과적으로 TLS는 SSL의 업데이트 버전이며 명칭만 다르다.
SSL/TLS 프로토콜을 사용한 웹사이트 URL은 HTTP 대신 HTTPS를 사용한다.
HTTPS 작동 방식
1. 핸드셰이크
클라이언트와 서버 간에 안전한 연결을 수립하기 위한 초기 단계이다. 핸드셰이크란 악수를 의미하며 이 과정에서 서로 암호화 방식을 협상하고 서버는 자신의 인증서를 클라이언트에게 제공한다. 클라이언트는 서버의 SSL/TLS 인증서가 올바른지 확인하고 웹 사이트의 공개키로 브라우저 난수, 서버 난수를 암호화하여 서버로 전송한다. 서버는 사이트의 비밀 키로 복호화한 값을 저장하고 세션키를 생성한다. 이 키는 앞으로 대칭키 암호화에 사용할 키가 된다.
2. 키 교환
비대칭 암호화를 사용하여 세션 동안 사용할 대칭 키를 안전하게 교환한다.
3. 데이터 전송
협상된 암호화 방식과 키를 사용하여 데이터를 암호화하고 전송한다.
4. 세션 종료
통신이 끝나면 사용된 세션 키는 폐기되고, 다음 통신에는 새로운 키가 생성된다.
HTTPS의 중요성
1. 개인 정보 보호
사용자의 민감한 정보를 보호하여 데이터 도난 및 유출을 방지한다.
2. 신뢰성
사용자가 안전한 사이트에 접속하고 있음을 보증한다. SSL/TLS 인증서는 사이트의 신뢰성을 간접적으로 나타낸다.
3. SEO개선
구글과 같은 주요 검색 엔진은 HTTPS를 사용하는 사이트를 우선적으로 순위에 반영하여, 사이트의 가시성을 높인다.
도메인에 HTTPS 사용해보기
Spring boot App에 SSL/HTTPS를 적용하기 위해선 다음과 같은 절차가 필요하다.
1. SSL 인증서 얻기
- Self Signed SSL 인증서
Self Signed SSL 인증서는 대표적으로 JKS(Java KeyStore)과 PKCS12(Public Key Cryptographic Standards)가 있다. JKS는 PKCS12와 비슷하지만 JAVA환경에서만 사용이 가능하고, PKCS12는 패스워드로 보호된 형식으로써, 여러 인증서 및 키를 포함할 수 있다. JAVA 뿐 아니라 여러 플랫폼에서 사용 가능하다.
자체 서명된 인증서로 아래 명령은 현재 디렉토리에 'myapp.keystore.p12' 라는 keystore 파일을 생성하는 명령어이다. 여기서 '-alias'는 keystore 내의 인증서를 식별하는 데 사용되며, '-validity' 는 인증서의 유효 기간(일 단위)를 설정한다.
keytool -genkeypair -alias myapp -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore myapp.keystore.p12 -validity 3650
생성된 keystore을 보면 'myapp.p12' SSL 인증서가 있을 것이다. 이를 spring boot 프로젝트의 resources 하위에 두면 된다.
- 정식 인증을 받은 SSL 인증서
배포 상황의 경우, App은 정식 인증을 받은 SSL 인증서를 사용해야 한다.
Let's Encrypt 같은 CA(Certification Authority, 인증기관)로부터 무료로 인증서를 발급받거나, 유료 인증서를 구매해 적용하면 된다.
https://letsencrypt.org/getting-started/
Getting Started - Let's Encrypt
Veure en català View in Thai Se på Dansk Auf Deutsch ansehen Ver en español Katso suomeksi Voir en Français לעבור לעברית Megtekintés magyar nyelven Lihat dalam Bahasa Indonesia Visualizza in italiano 日本語で表示する 한국어로
letsencrypt.org
해당 사이트의 Getting Started 탭을 확인해보면 Cerbot 클라이언트를 이용해 발급받으라고 한다.
putty를 통해 서버에 접속해 설치 했고, 설치 방법에 대해서는 https://certbot.eff.org/instructions 에 자세히 나와있다.
소프트웨어와 OS를 선택하면 설치 방법부터 발급까지 알려준다.
[cerbot 설치]
sudo apt-get update
sudo apt-get install certbot
[cerbot에게 인증서 발급 요청]
sudo certbot certonly --standalone -d yourdomain.com
만료는 90일 이후이다. 갱신은 certbot renew로 하면 된다고 한다.
그런데 Let's Encrypt로 생성한 키파일은 PEM 포맷이다. PKCS12를 사용하기 위해 .p12 파일로 인증서를 변환해준다.
sudo openssl pkcs12 -export -in /etc/letsencrypt/live/본인도메인/fullchain.pem -inkey /etc/letsencrypt/live/dutypark.o-r.kr/privkey.pem -out keystore.p12 -name tomcat -CAfile /etc/letsencrypt/live/본인도메인/chain.pem -caname root
이렇게 하면 keystore.p12 파일이 생긴다. 그리고 해당 파일을 resources 하위에 둔다.
2. application.yml 수정
생성된 keystore 파일을 Spring boot 애플리케이션에 적용하기 위해 application.yml에 다음과 같이 추가한다.
server:
port: 443
ssl:
key-store: classpath:myapp.keystore.p12
key-store-password: yourKeystorePassword
keyStoreType: PKCS12
keyAlias: myapp
여기서 server.port는 HTTPS 연결에 사용할 포트 번호를 설정한다. 일반적으로 8443이 사용되는데 프로젝트에선 443을 사용했다. key-store 경로는 프로젝트의 'resources' 디렉토리에 keystore 파일을 위치시키는 경우 'classpath:' 접두사를 사용하여 지정할 수 있다.
3. 리다이렉션 설정(선택)
만약 이전에 http로 접속했던 사용자가 다시 접속을 하려면 접속이 되지 않는다. http://naver.com/ 로 접속을 하면 https로 자동 리다이렉트 되는 것처럼 조치가 필요하다. 즉, http로 접속 시 https로 연결할 방법이 필요한 것이다. Spring Security 설정을 사용하거나, 커스텀 리다이렉션 로직을 구현할 수 있는데 Spring Security를 사용하여 코드를 작성해 보겠다.
Spring Security 의존성이 추가되었다는 가정 하에 진행한다.
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.requiresChannel()
.anyRequest()
.requiresSecure();
}
}
이 설정은 모든 요청을 HTTPS를 통해 수행되도록 요구한다.
1. sudo certbot renew (갱신)
2. keystore.p12 파일 생성 (renew만 하고 예전 keystore을 그대로 사용하면 유효기간은 예전 그대로이다.)
sudo openssl pkcs12 -export -in /etc/letsencrypt/live/도메인/fullchain.pem -inkey /etc/letsencrypt/live/도메인/privkey.pem -out /etc/letsencrypt/live/도메인/keystore.p12 -name tomcat -CAfile /etc/letsencrypt/live/도메인/chain.pem -caname root
3. 재시작
'개발' 카테고리의 다른 글
오토 스케일링 (Auto Scaling) (0) | 2024.01.30 |
---|---|
Docker (0) | 2023.10.03 |
Controller @RequestParam, @RequestBody, @PathVariable (0) | 2023.09.18 |
초기 Git 설정 + 연동 (0) | 2023.08.14 |
Response Success/Fail (0) | 2023.07.11 |