서버 개발자를 지망하며 다양한 학습을 진행했다. 하지만 내가 공부한 학습에서는 보안에 대한 내용은 많이 없었다. 있어봐야 공개키 비공개키에 대한 학습뿐이었다. 이러한 와중에 보다 확실한 보안 개념이 필요해졌다.
그 이유는 장애없는 서비스를 만들기 위해서는 백날 코드만 완벽하게 짠다고해서 달성되는 것이 아니란 것을 어느정도 깨닫기 시작한 시점부터이다. 장애없는 서비스를 만드는 개발자가 되기 위해, 좋은 개발자가 되기 위해 보안에 대한 개념을 보다 명확히 알고 보다 가치있는 서비스를 개발하자
보안을 중점으로 다루기전에 간단하게 HTTP 통신에 대해서 알 필요가 있다고 생각한다. 여기서는 HTTP에 대해서 중점으로 다루는 것이 아니라 간단하게 위키의 내용을 인용하겠다.
HTTP (HyperText Transfer Protocol) W3 상에서 정보를 주고받을 수 있는 프로토콜이다, 주로 HTML 문서를 주고받는 데에 쓰이며 주로 TCP를 사용하고 HTTP/3 부터는 UDP를 사용하며 80번 포트를 사용한다. - wikipedia.org -
간단하게 HTTP에 대해서 알아보았다. 그렇다면 이번주제가 되는 보안의 영역으로 들어가보자
HTTP는 클라이언트와 서버간의 통신을 주고받게 해주는 가장 기초적인 프로토콜 이다. 이 프로토콜은 기초적인 프로토콜인 만큼 얼마든지 접근이 가능하다는 엄청난 문제점을 가지고 있다. 즉, 우리가 특정 사이트에 "인가"를 받기 위해 전송하는 정보를 누군가 얼마든지 가로채서 조작을 하거나 나와 같은 권한을 가질 수 있다는 것을 의미한다.
HTTP 통신에서는 보안이 적용되지 않기 때문에 id, password가 공개되어 서버에 요청이 되는데 이때 누구나 접근가능하기 때문에 언제든지 id, password를 탈취 당할 수 있습니다.
이를 막기위해서 HTTPS 라는 개념이 등장하게 되는데 HTTPS 단순하게 말하면 HTTP에 보안에 적용된 통신이라는 의미 이다.
HTTPS 가 HTTP 통신에 보안이 적용된 통신이라고 했는데 보안은 어떻게 적용되는 것일까?? 이때 사용되는 것이 SSL (보안 소켓 계층)이며 SSL을 통신에 적용하여 통신 보안을 보다 강화 한다.
SSL을 서버와 브라우저 사이에 안전하게 암호화된 연결을 만들 수 있게 도와주고, 서버 브라우저가 민감한 정보를 주고받을 때 이것이 도난당하는 것을 막아주는 역할을 한다.
위에서 간단하게 SSL이 어떤 역할을 하는지 알아보았다. 그렇다면 정확하게 SSL이란 무엇일까??? 일단 SSL은 클라이언트와 서버간의 통신을 제3자가 보증해주는 전자화된 문서이다.
개념
이점
여기서 핵심은 SSL이 공개키/대칭키 기반의 "암호화" 된 문서라는 것이다.
그렇다면 암호화는 어떻게 진행되는 것일까? 암호화 방식에는 크게 두 가지 방식이 존재한다. 대칭키 방식과 비공개키 방식으로 암호화를 할 수 있는데 우선 결론을 말하자면 현재 웹 브라우저는 통신에 두 가지 방식을 모두 혼용하고 보안을 지키고 있다.
암호화란 무엇일까
암호화란 말 그대로의 의미인데 클라이언트가 서버로 보내는 데이터들을 알아볼 수 없도록 값을 변경하여 암호화 하여 데이터를 보내는 것을 의미한다.
이렇게되면 우리의 데이터 정보가 외부에 노출되어도 값을 알아볼 수 없기 때문에 보다 안전한 방식의 통신을 할 수 있다.
KEY
데이터가 암호화 되는 것은 KEY를 통해 암호화가 되는데 이말은 즉 KEY가 있어야 다시 복호화 할 수 있다는 것을 의미한다.
지금까지의 내용을 정리해보면 데이터를 안전하게 전송하기 위해서 암호화 하여 보내는데 이때 암호화 할 때 필요한 것이 "Key" 라는 개념이다. 우리는 Key를 통해 데이터를 암호화하고 다시 Key 를 이용해서 복호화 할 수 있다.
그렇다면 결론은 서버에서도 원본의 데이터를 보기 위해서는 KEY가 필요하다는 것인데 이렇게 동일한 KET를 통해 암호화와 복호화를 진행하는 것을 대칭키 방식이라고 한다.
대칭키 방식에는 단점이자 보안상의 한계가 뚜렷하다. 바로 암호화를 하는 KEY가 서버측에도 있어야 원본의 데이터를 볼 수 있다는 것인데
이 "KEY를 전달하는 것이 최초에 Hand Shacke 하는 과정에서 필수적으로 주고 받아야한다" 라는 단점이자 한계가 있다.
이게 왜 단점이냐 하면 최초에 KEY가 전달 될 때 이 KEY를 역시 누구나 접근해서 볼 수 있다는 점이 가장 큰 단점 이다.
그렇다면 이러한 문제를 어떻게 해결할 까? 이를 해결하기 위한 방법으로 등장한 개념이 바로 공개키 방식의 암호화가 등장하게 된다.
공개키 방식은 두개의 키를 갖게 되는데 A키로 암호화를 하면 B키로 복호화 할 수 있고, B키로 암호화하면 A키로 복호화 할 수 있는 방식이다. 이 방식에 착안해서 두개의 키 중 하나를 비공개키 (개인키, 비밀키)로 하고 나머지를 공개키로 지정한다.
비공개키는 자신만이 가지고 있고, 공개키를 타인에게 제공을 하는데 공개키를 제공 받은 타인은 공개키를 이용해서 데이터를 암호화 한다. 그리고 공개키를 통해 암호화된 데이터를 비공개키를 가지고 있는 사람한테 전송을 하는데 비공개키의 소유자는 이 키를 이용해서 암호화된 정보를 다시 복호화 할 수 있다. 이 과정에서 공개키를 유출하더라도 비공개키를 모르면 정보를 복호화 할 수 없기 때문에 안전하다.
즉, 공개키로는 암호화만 가능하고 공개키로는 복호화를 할 수 없게 한 것이다.
이제 우리는 이 개념을 응용하는 '전자 서명' 이라는 것을 이해할 필요가 있다.
위에서 언급했지만 다시금 개념을 정리해보자 공개키는 인터넷상에 공개하는 키이다. 그리고 공개키를 통해 암호화된 데이터를 복호화하기 위해서는 비밀키가 필요하다. 즉, 비밀키를 가지지 않는다면 누구도 데이터를 복호화 하지 못함을 의미한다.
이걸 응용하면 다음과 같은 개념이 나온다. "공격자가 뿌린 공개키를 다운 받는 것이 아니라면 우리는 신뢰할 수 있는 사용자가 뿌린 공개키를 통해 다시 암호화 된 데이터를 다시 복호화 할 수 있다는 것이다."
(여기서 신회할 수 있는 서버 임을 검증하는 것이 CA 라는 기관이 있는데 이 개념은 조금있다가 설명하겠다.)
여기서 "주목할 것은 신뢰할 수 있는 사용자" 라는 개념이다. 더 이상 암호화가 단순하게 데이터를 보호하기 위한 개념으로만 사용되는 것이 아니라는 것이며 즉, 비밀키를 가지고 암호화를 진행한 A라는 정보를 보기 위해서는 반드시 비밀키와 쌍을 이루는 공개키를 가져야 함을 뜻하고 이 공개키는 엄격한 검증을 CA 라는 기관이 진행하여 공개키를 발행하게 된다.
이렇게 암호화된 데이터가 공개키로 복호화된다는 것은 공개키와 쌍을 이루는 개인키에 의하여 암호화되었다는 것을 뜻한다. 따라서 데이터의 제공자의 신원 확인이 보장된다는 뜻이기 때문에 "전자서명" 에 이용하게 된다.
지금까지 암호화의 원리를 알아보았으니 이제 SSL 프로토콜이 동작하는 방법을 알아보자
즉, 클라이언트와 서버가 주고 받는 실제 정보는 대칭키 방식으로 암호화하고, 대칭키 방식으로 암호화된 실제 정보를 복호화할 때 사용할 대칭키는 공개키 방식으로 암호화해서 클라이언트와 서버가 주고 받는다.
암호화된 데이터를 서버와 통신하는 단계
위의 단계를 "Hand Shake" 라고 하는 과정에서 이루어지게 되는데 이말은 모든 SSL 연결은 반드시 Hand Shake 과정을 거쳐야 한다는 것을 의미한다.
이렇게 Hand Shake를 하게되면 SSL을 통해 클라이언트 및 서버가 통신하는 보안 키를 설정할 수 있게 된다.
a. 클라이언트가 서버에 접속 - Client Hello
b. 서버는 Client Hello 에 대한 응답으로 Server Hello 를 하게 된다. 이 단계에서 주고 받는 정보는 아래와 같다.
c. 클라이언트는 서버의 인증서가 CA에 의해서 발급된 것인지를 확인하기 위해서 클라이언트에 내장된 CA 리스트를 확인한다.
위에서 클라이언트와 서버는 각각 랜던 데이터를 생성한다고 했다. 이 랜덤 데이터들은 서로 조합되어 pre master secret 이란 키가 된다.
이 키는 세션 단계에서 데이터를 주고 받을 때 암호화 하기 위해서 사용될 것이고 이 때 사용할 암호화 기법은 대칭키이기 때문에 pre master secret 같은 제 3자에게 절대로 노출되어서는 안된다.
그럼 이 pre master secret 값을 어떻게 서버에게 전달할 것인가?
그럼 서버의 공개키는 어떻게 구할 수 있을까?
d. 서버는 클라이언트가 전송한 pre master secret 값을 자신의 비공개키로 복호화한다.
Sample Controller 만들기
먼저 스프링 이니셜라이저 를 통해 스프링 부트 프로젝트를 생성하고 간다하게 Controller 를 설정 한다.
간단하게 컨트롤러를 작성 했고 Run Application을 통해 서버를 실행 시킵니다. 그리고 지정한 URL로 요청을 보낸다 하지만 아직은 SSL을 적용하지 않았기 때문에 전혀 문제 없이 요청에 대해 응답을 할 것이다.
결과는 http로 요청 했기 때문에 전혀 보안상 이슈 없이 원하는 결과물을 볼 수 있다.
이제 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" 이 뜨는 것을 볼 수 있다.
지금까지 어떻게 통신에서 보안이 확립된 통신이 이루어지는지에 대해서 알아보았다. 내용을 정리해보자
정리