클라이언트와 서버의 통신은 어떻게 안전하게 통신을 할 수 있을까?

to0·2021년 3월 21일
4
post-custom-banner

들어가며

서버 개발자를 지망하며 다양한 학습을 진행했다. 하지만 내가 공부한 학습에서는 보안에 대한 내용은 많이 없었다. 있어봐야 공개키 비공개키에 대한 학습뿐이었다. 이러한 와중에 보다 확실한 보안 개념이 필요해졌다.

그 이유는 장애없는 서비스를 만들기 위해서는 백날 코드만 완벽하게 짠다고해서 달성되는 것이 아니란 것을 어느정도 깨닫기 시작한 시점부터이다. 장애없는 서비스를 만드는 개발자가 되기 위해, 좋은 개발자가 되기 위해 보안에 대한 개념을 보다 명확히 알고 보다 가치있는 서비스를 개발하자


HTTP

보안을 중점으로 다루기전에 간단하게 HTTP 통신에 대해서 알 필요가 있다고 생각한다. 여기서는 HTTP에 대해서 중점으로 다루는 것이 아니라 간단하게 위키의 내용을 인용하겠다.

HTTP (HyperText Transfer Protocol) W3 상에서 정보를 주고받을 수 있는 프로토콜이다, 주로 HTML 문서를 주고받는 데에 쓰이며 주로 TCP를 사용하고 HTTP/3 부터는 UDP를 사용하며 80번 포트를 사용한다. - wikipedia.org -

간단하게 HTTP에 대해서 알아보았다. 그렇다면 이번주제가 되는 보안의 영역으로 들어가보자


HTTPS

HTTP는 클라이언트와 서버간의 통신을 주고받게 해주는 가장 기초적인 프로토콜 이다. 이 프로토콜은 기초적인 프로토콜인 만큼 얼마든지 접근이 가능하다는 엄청난 문제점을 가지고 있다. 즉, 우리가 특정 사이트에 "인가"를 받기 위해 전송하는 정보를 누군가 얼마든지 가로채서 조작을 하거나 나와 같은 권한을 가질 수 있다는 것을 의미한다.

HTTP 통신에서는 보안이 적용되지 않기 때문에 id, password가 공개되어 서버에 요청이 되는데 이때 누구나 접근가능하기 때문에 언제든지 id, password를 탈취 당할 수 있습니다.

이를 막기위해서 HTTPS 라는 개념이 등장하게 되는데 HTTPS 단순하게 말하면 HTTP에 보안에 적용된 통신이라는 의미 이다.


SSL

HTTPS 가 HTTP 통신에 보안이 적용된 통신이라고 했는데 보안은 어떻게 적용되는 것일까?? 이때 사용되는 것이 SSL (보안 소켓 계층)이며 SSL을 통신에 적용하여 통신 보안을 보다 강화 한다.

SSL을 서버와 브라우저 사이에 안전하게 암호화된 연결을 만들 수 있게 도와주고, 서버 브라우저가 민감한 정보를 주고받을 때 이것이 도난당하는 것을 막아주는 역할을 한다.


SSL이란 무엇일까?

위에서 간단하게 SSL이 어떤 역할을 하는지 알아보았다. 그렇다면 정확하게 SSL이란 무엇일까??? 일단 SSL은 클라이언트와 서버간의 통신을 제3자가 보증해주는 전자화된 문서이다.

개념

  • SSL은 Secure Socket Layer의 약자로 보안 소켓 레이이어이다.
  • SSL은 443 Port 를 이용하며 https://를 사용하게 된다.
  • SSL은 Netscape 사에서 웹서버와 웹브라우저간의 보안을 위해 만들어졌으며 공개키/비공개키 기반으로 작동한다.

이점

  • 통신 내용이 공격자에게 노출되는 것을 막을 수 있다,
  • 클라이언트가 접속하려는 서버가 신뢰 할 수 있는 서버인지를 판단할 수 있다.
  • 통신 내용의 악의적인 변경을 방지할 수 있다.

여기서 핵심은 SSL이 공개키/대칭키 기반의 "암호화" 된 문서라는 것이다.


암호화

그렇다면 암호화는 어떻게 진행되는 것일까? 암호화 방식에는 크게 두 가지 방식이 존재한다. 대칭키 방식과 비공개키 방식으로 암호화를 할 수 있는데 우선 결론을 말하자면 현재 웹 브라우저는 통신에 두 가지 방식을 모두 혼용하고 보안을 지키고 있다.

암호화란 무엇일까

암호화란 말 그대로의 의미인데 클라이언트가 서버로 보내는 데이터들을 알아볼 수 없도록 값을 변경하여 암호화 하여 데이터를 보내는 것을 의미한다.

이렇게되면 우리의 데이터 정보가 외부에 노출되어도 값을 알아볼 수 없기 때문에 보다 안전한 방식의 통신을 할 수 있다.

KEY

데이터가 암호화 되는 것은 KEY를 통해 암호화가 되는데 이말은 즉 KEY가 있어야 다시 복호화 할 수 있다는 것을 의미한다.


대칭키

지금까지의 내용을 정리해보면 데이터를 안전하게 전송하기 위해서 암호화 하여 보내는데 이때 암호화 할 때 필요한 것이 "Key" 라는 개념이다. 우리는 Key를 통해 데이터를 암호화하고 다시 Key 를 이용해서 복호화 할 수 있다.

그렇다면 결론은 서버에서도 원본의 데이터를 보기 위해서는 KEY가 필요하다는 것인데 이렇게 동일한 KET를 통해 암호화와 복호화를 진행하는 것을 대칭키 방식이라고 한다.


대칭키의 단점

대칭키 방식에는 단점이자 보안상의 한계가 뚜렷하다. 바로 암호화를 하는 KEY가 서버측에도 있어야 원본의 데이터를 볼 수 있다는 것인데

이 "KEY를 전달하는 것이 최초에 Hand Shacke 하는 과정에서 필수적으로 주고 받아야한다" 라는 단점이자 한계가 있다.

이게 왜 단점이냐 하면 최초에 KEY가 전달 될 때 이 KEY를 역시 누구나 접근해서 볼 수 있다는 점이 가장 큰 단점 이다.

그렇다면 이러한 문제를 어떻게 해결할 까? 이를 해결하기 위한 방법으로 등장한 개념이 바로 공개키 방식의 암호화가 등장하게 된다.


공개키

공개키 방식은 두개의 키를 갖게 되는데 A키로 암호화를 하면 B키로 복호화 할 수 있고, B키로 암호화하면 A키로 복호화 할 수 있는 방식이다. 이 방식에 착안해서 두개의 키 중 하나를 비공개키 (개인키, 비밀키)로 하고 나머지를 공개키로 지정한다.

비공개키는 자신만이 가지고 있고, 공개키를 타인에게 제공을 하는데 공개키를 제공 받은 타인은 공개키를 이용해서 데이터를 암호화 한다. 그리고 공개키를 통해 암호화된 데이터를 비공개키를 가지고 있는 사람한테 전송을 하는데 비공개키의 소유자는 이 키를 이용해서 암호화된 정보를 다시 복호화 할 수 있다. 이 과정에서 공개키를 유출하더라도 비공개키를 모르면 정보를 복호화 할 수 없기 때문에 안전하다.

즉, 공개키로는 암호화만 가능하고 공개키로는 복호화를 할 수 없게 한 것이다.

이제 우리는 이 개념을 응용하는 '전자 서명' 이라는 것을 이해할 필요가 있다.


전자 서명

위에서 언급했지만 다시금 개념을 정리해보자 공개키는 인터넷상에 공개하는 키이다. 그리고 공개키를 통해 암호화된 데이터를 복호화하기 위해서는 비밀키가 필요하다. 즉, 비밀키를 가지지 않는다면 누구도 데이터를 복호화 하지 못함을 의미한다.

이걸 응용하면 다음과 같은 개념이 나온다. "공격자가 뿌린 공개키를 다운 받는 것이 아니라면 우리는 신뢰할 수 있는 사용자가 뿌린 공개키를 통해 다시 암호화 된 데이터를 다시 복호화 할 수 있다는 것이다."

(여기서 신회할 수 있는 서버 임을 검증하는 것이 CA 라는 기관이 있는데 이 개념은 조금있다가 설명하겠다.)

여기서 "주목할 것은 신뢰할 수 있는 사용자" 라는 개념이다. 더 이상 암호화가 단순하게 데이터를 보호하기 위한 개념으로만 사용되는 것이 아니라는 것이며 즉, 비밀키를 가지고 암호화를 진행한 A라는 정보를 보기 위해서는 반드시 비밀키와 쌍을 이루는 공개키를 가져야 함을 뜻하고 이 공개키는 엄격한 검증을 CA 라는 기관이 진행하여 공개키를 발행하게 된다.

이렇게 암호화된 데이터가 공개키로 복호화된다는 것은 공개키와 쌍을 이루는 개인키에 의하여 암호화되었다는 것을 뜻한다. 따라서 데이터의 제공자의 신원 확인이 보장된다는 뜻이기 때문에 "전자서명" 에 이용하게 된다.


SSL의 동작방법

지금까지 암호화의 원리를 알아보았으니 이제 SSL 프로토콜이 동작하는 방법을 알아보자

  • 결론부터 말하자면 SSL은 암호화된 데이터를 전송하기 위해서 공개키와 대칭키를 혼합해서 사용한다.

즉, 클라이언트와 서버가 주고 받는 실제 정보는 대칭키 방식으로 암호화하고, 대칭키 방식으로 암호화된 실제 정보를 복호화할 때 사용할 대칭키는 공개키 방식으로 암호화해서 클라이언트와 서버가 주고 받는다.

  • 실제 데이터: 대칭키
  • 대칭키의 키: 공개키

WHY?

  • 이렇게 하는 이유는 공개키는 자원소모가 크다. 따라서 모든 통신을 공개키 방식으로 암호화하고, 복호화하면 너무 많은 자원을 소모하기 때문에 실제로는 데이터를 공개키로 암호화 하는 것은 가능하지 않다.
  • 따라서 현재는 대칭키의 보안을 보장해줄 대칭키 암호화"공개키" 를 통해 암호화 한다.

SSL 클라이언트와 서버가 통신하는 단계

암호화된 데이터를 서버와 통신하는 단계

  1. 사용할 프로토콜 버전에 동의
  2. 암호화 알고리즘 선택
  3. 디지털 인증서를 교환하고 유효성을 검사하여 서로 인증
  4. 비대칭 암호화 기술을 사용하여 공유 비밀키를 생성, 그런 다음 SSL 인증서는 공개키를 사용하여 메시지를 대칭 암호화 방식으로 암호화

위의 단계를 "Hand Shake" 라고 하는 과정에서 이루어지게 되는데 이말은 모든 SSL 연결은 반드시 Hand Shake 과정을 거쳐야 한다는 것을 의미한다.

이렇게 Hand Shake를 하게되면 SSL을 통해 클라이언트 및 서버가 통신하는 보안 키를 설정할 수 있게 된다.


전반적인 SSL 동작과정

a. 클라이언트가 서버에 접속 - Client Hello

  • 가장 먼저 클라이언트가 서버에 접속을 시도한다. 이 단계에서 클라이언트는 서버쪽으로 클라이언트가 생성한 랜덤 데이터를 보낸다.
  • 클라이언트가 지원하는 암호화 방식들은 여러가지가 있는데 클라이언트와 서버가 지원하는 암호화 방식이 서로 다를 수 있다 따라서 상호간에 어떤 암호화 방식을 사용할 것인지에 대한 협상을 진행해야 한다. 이 협상을 위해서 클라이언트 측에서는 자신이 사용할 수 있는 암호화 방식을 전송한다.
  • 세션 아이디: 이미 SSL 핸드쉐이킹이 이루어졌다면 비용과 시간을 절약하기 위해서 기존의 세션을 재활용하게 되는데 이 때 사용할 연결에 대한 식별자를 서버 측으로 전송하게 된다.

b. 서버는 Client Hello 에 대한 응답으로 Server Hello 를 하게 된다. 이 단계에서 주고 받는 정보는 아래와 같다.

  • 서버 측에서 생성한 랜덤 데이터
  • 서버가 선택한 클라이언트의 암호화 방식: 클라이언트가 전달한 암호화 방식 중에서 서버 쪽에서도 사용할 수 있는 암호화 방식을 선택해서 클라이언트로 전달한다. 이로써 암호화 방식에 대한 협상이 종료되고 서버와 클라이언트는 이 암호화 방식을 이용해서 정보를 교환한다.
  • "인증서"

c. 클라이언트는 서버의 인증서가 CA에 의해서 발급된 것인지를 확인하기 위해서 클라이언트에 내장된 CA 리스트를 확인한다.

  • CA 리스트를 확인하는데 이때 인증서가 없다면 경고 메시지를 출력한다.
  • 인증서가 CA에 의해서 발급된 것인지를 확인하기 위해서 클라이언트에 내장된 CA의 공개키를 이용해서 인증서를 복호화 한다.
  • 복호화에 성공했다면 인증서는 CA의 개인키로 암호화된 문서임이 암시적을 보증된 것이다. 즉 인증서를 전송한 서버를 믿을 수 있게 된 것이다.

pre master secret

위에서 클라이언트와 서버는 각각 랜던 데이터를 생성한다고 했다. 이 랜덤 데이터들은 서로 조합되어 pre master secret 이란 키가 된다.

이 키는 세션 단계에서 데이터를 주고 받을 때 암호화 하기 위해서 사용될 것이고 이 때 사용할 암호화 기법은 대칭키이기 때문에 pre master secret 같은 제 3자에게 절대로 노출되어서는 안된다.

그럼 이 pre master secret 값을 어떻게 서버에게 전달할 것인가?

  • 이 때 사용 방법이 바로 공개 키 방식이다.
  • 서버의 공개키로 pre master secret 값을 암호화해서 서버로 전송하면 서버는 자신의 비공개키로 안전하게 복호화 할 수 있다.

그럼 서버의 공개키는 어떻게 구할 수 있을까?

  • 서버로부터 받은 인증서 안에 공개키가 들어가 있고 이 서버의 공개키를 이용해서 pre master secret 값을 암호화한 후에 서버로 전송하면 안전하게 전송을 할 수 있다.

d. 서버는 클라이언트가 전송한 pre master secret 값을 자신의 비공개키로 복호화한다.

  • 이로서 서버와 클라이언트가 모두 pre master secret 값을 공유하게 되었다. 그리고 서버와 클라이언트는 모두 일련의 과정을 처쳐 pre master secret 값을 master secret 값으로 만든다.
  • master secret 는 session key를 생성하는데 이 session key 값을 이용해서 서버와 클라이언트는 데이터를 대칭키 방식으로 암호화 한 후에 주고 받는다. 이렇게해서 세션키를 클라이언트와 서버가 공유하게 되어 안전하게 통신이 가능해진다.

실습하기

  • Spring boot 를 통해서 로컬에서 간단하게 서버를 띄우고 CA 인증을 받은 SSL 은 아니지만 직접 만들어낸 SSL을 통해서 어떻게 브라우저가 반응하는지 살펴보자

Sample Controller 만들기

먼저 스프링 이니셜라이저 를 통해 스프링 부트 프로젝트를 생성하고 간다하게 Controller 를 설정 한다.

  • 그리고 먼저 해볼 것은 https 가 아니라 단순 http로 접근할 수 있도록 SSL 설정 없이 진행해본다.

간단하게 컨트롤러를 작성 했고 Run Application을 통해 서버를 실행 시킵니다. 그리고 지정한 URL로 요청을 보낸다 하지만 아직은 SSL을 적용하지 않았기 때문에 전혀 문제 없이 요청에 대해 응답을 할 것이다.

결과는 http로 요청 했기 때문에 전혀 보안상 이슈 없이 원하는 결과물을 볼 수 있다.


SSL을 적용해서 https로 접근하기

이제 SSL을 적용해서 https 로 접근하는 실습을 진행할 것인데 터미널에서 몇가지 설정을 해주고 application.properties에 그 설정을 적용시키면 HTTPS 접근이 가능해진다.

먼저 터미널로 아래의 명령어를 실행한다.

keytool -genkey 
  -alias tomcat 
  -storetype PKCS12 
  -keyalg RSA 
  -keysize 2048 
  -keystore keystore.p12 
  -validity 400

그리고 application.properties에 다음 내용을 작성한다.

server.ssl.key-store: keystore.p12
server.ssl.key-store-password: [개인이 설정한 비밀번호]
server.ssl.keyStoreType: PKCS12
server.ssl.keyAlias: tomcat

그리고 다시 Run Application을 통해 서버를 동작시키고 기존의 주소에 요청을 보내본다.

그러면 아래와 같이 TLS (SSL) 이 필요하다는 창이 뜨면서 정상적으로 요청이 가지 않은 것을 알 수 있다.

이제 다시 URL에 https:// 를 붙이고 보내보자

그럼 이러한 메세지가 뜨는데 이 메시지는 인증서가 CA에서 발급한 공인된 인증서가 아니기 때문에 조심하라고 메시지를 보내는 것이다.

우리는 로컬에서 만든 것이기 때문에 신뢰하고 이 웹사이트 방문을 클릭해서 요청을 보내면 다시 "Hello SSL" 이 뜨는 것을 볼 수 있다.


마무리

지금까지 어떻게 통신에서 보안이 확립된 통신이 이루어지는지에 대해서 알아보았다. 내용을 정리해보자

정리

  • HTTPS 는 HTTP 프로토콜에 SSL 인증서를 사용해서 보안이 강화된 프로토콜이다.
  • SSL 인증서는 공개키/비공개 키 기반으로 동작한다.
  • 공개키와 비공개키를 통해서 전자서명이란 인증 방식이 나왔고 전자 서명을 통해 믿을 수 있는 사용자, 서버 임을 증명할 수 있다.
  • 이를 사용하기 위해서 클라이언트와 서버는 Hand Shake 라는 과정을 통해 데이터 통신을 하기 이전에 서로의 신원을 증명하고 보안을 확립한다.

참고

profile
🖌️ 성장을 위한 나의 컬럼 저장소
post-custom-banner

0개의 댓글