[홈서버 구축기] HTTPS와 SSL 인증서 (이론)
참고: https://opentutorials.org/course/228/4894
암호화의 유래는 오래되었다. 수천년 전에도 일종의 암호를 적용했다는 기록이 남아있다.
이런 방식은 모두 대칭키 암호 방식으로 암호화(encrypt)하는 키(비밀)와 복호화(decrypt)하는 키(비밀)가 같다.
이 경우 ‘키’를 안전하게 전송하는 것이 다시 어려운 숙제가 된다.
그래서 나온 방식이 비대칭키 암호화이다. (Asymetric Cryptography)
비대칭키 암호화에는 키가 두 가지가 있고, 이 둘은 쌍으로써 하나의 키로 암호화 한 것은 쌍인 다른 키로만 복호화 할 수 있고 암호화한 키로도 복호화를 할 수 없다.
비대칭키 암호화를 다른 말로는 공개키 암호화 방식이라고 하는데 이는 비대칭키의 응용을 고려해서 쓰이는 말 같다.
이 두 개의 키 중에서 하나는 공개해서 대중에게 널리 공유하고 (공개키), 다른 하나는 혼자만 비밀리에 갖고 쓰는 것이다. (비공개키 혹은 개인키)
가령 어떤 공주가 있는데 그 공주를 사모하는 청년은 여럿이 있다.
이 청년들은 자신의 마음을 담은 사랑 편지를 그 ‘공주’만 읽기를 바란다. 다른 사람이 그 편지를 읽을 수 있게 되면 너무 창피할 것 같다.
이때 공주가 비대칭키 한쌍을 만들어 하나(비공개키 혹은 개인키)는 자신이 갖고 있고, 다른 키(공개키)는 청년들에게 전달하며 알려준다.
‘여러분의 편지를 이 공개키로 암호화해서 제게 보내시면 다른 사람은 절대 못보고 저만 볼 수 있으니 안심하고 편지를 보내주세요~~’
청년들은 모두 동일하게 그 공개키를 갖고 있다. 그 키를 나만 갖고 있다고 유리할 것도 전혀 없다. 모두가 가져도 아무 상관이 없다. 하지만 개인키는 공주만 갖고 있어야지 그 개인키가 유출되면 청년들의 편지를 다른 사람이 해독해서 읽을 수 있게 된다.
거꾸로 공주가 개인키로 암호화한 편지는 공개키를 갖고 있는 아무나 다 읽을 수 있다. 공주가 철수 청년만 읽기를 바래서 개인키로 암호화해서 보낸 것은 공개키를 갖고 있는 민수 청년도 해독해서 읽을 수 있다. 즉, 이 방향 (개인키로 암호화하고 공개키로 복호화하는 방향)은 보안성에는 문제가 있고, 대신 그 편지는 (공주가 개인키를 잃어버린 것이 아니라면) 공주가 썼다는 것을 100% 확신할 수 있다. 왜냐하면 공개키로 해독이 된다는 것은 그 공개키와 쌍이 되는 개인키로 암호화를 했다는 것이고 그 개인키는 공주만 갖고 있기 때문이다. 이를 ‘서명’이라고 한다. 예전 영화 등에서 나오는 ‘인장’과 비슷한 역할이다.
정리하면 공개키로 암호화한 것은 개인키를 갖고 있는 대상만 해독해서 읽을 수 있다.
개인키로 암호화한 것은 모든 공개키 소유자가 읽을 수 있어서 보안성이 주가 아니라 개인키를 가진 사람이 작성했다는 서명용으로 쓰일 수 있다.
공주를 서버로 대치하고, 청년을 다수의 서비스 이용자들로 치환해서 생각해보자.
서버에서는 공개키와 개인키를 쌍으로 만들어 공개키는 모두에게 나눠줘서 서버에게 비밀리에 내용을 보낼 때에는 그 공개키로 암호화하라고 한다. 이렇게 비밀리에 전송된 내용은 서버만 해독할 수 있다.
서버가 개인키로 암호화해서 전송하는 것은 공개키를 가진 자는 누구나 해독할 수 있기에 보안성은 없지만 그 공개키로 해독이 된다는 것은 확실히 서버가 보낸 것이라는 것을 확신할 수 있다.
딱 정확하지는 않지만 ‘인증서’라는 주제에서 말하는 보안, 인증의 내용이 얼핏 이해가 된다.
그럼 실제로는 어떠한가, 좀 더 들어가보자.
위에서 말한 것처럼 서버가 개인키로 암호화한 것은 보안이 주가 아니라 인증이 주이다. 그럼 서버가 특정개인에게만 비밀리에 보내고 싶을 때는 어떻게 하나? 개인이 여럿일 수 있는데 서버가 그 개인별 공개키를 모두 가지고 있을수는 없지 않은가…
비대칭키는 위의 장점이 있지만 치명적인 단점이 있다. 암호화를 하거나 복호화를 할때 많은 연산을 필요로 한다. CPU가 많이 일을 처리해야한다는 것이고, CPU 성능이 딸리면 속도가 늦게 되고, 암호화를 할 데이터가 많으면 그만큼 CPU가 일을 많이 해야하고 시간도 오래걸린다는 것이다. 따라서 전송되는 많은 데이터를 비대칭키로 암호화하는 것은 속도 문제로 현실적으로 쓸 수가 없다.
반대로, 대칭키는 키전송의 위험부담이 있지만 속도가 빠르다는 장점이 있다.
따라서 이 대칭키와 비대칭키를 함께 쓰면 서로의 단점을 상쇄할 수가 있다. (키 전송의 보안 취약점과 암호화 속도 문제)
즉, 실제 전송되는 데이터는 대칭키로 암호화해서 전송하고, 이 대칭키 자체는 비대칭키로 암호화해서 전송해서 서버와 클라이언트간에 비밀리에 공유하고, 서버의 신원확인(서명)은 서버의 개인키로 하면 대부분의 문제가 해결이 된다. (한가지 문제가 있는데 이는 후에 기술하겠다.)
이게 대략적인 인증서의 메커니즘이다.
서버에 인증서가 있는 상황을 가정해보자. (인증서의 발급 과정은 후에 기술하겠다.)
인증서의 목적은 두가지이다. 클라이언트와 서버간에 빠르고 안전한 통신을 하기 위함과 서버의 신원확인을 하기 위함이다.
인증서에는 서버의 정보 (서버 이름, 소유자 e-mail 등)와 서버의 공개키가 들어있다. 그리고 누가 인증을 했는지를 가리키는 인증자의 정보가 있고, 이런 정보들을 digest(hash)해서 해당 인증자의 개인키로 서명을 하여 인증서에 덧붙여 인증서가 최종 완성된다. 물론 어떤 방식으로 digest(hash)했는지도 같이 기록되어있다. 이때 인증자가 서버 자신인 경우 self-signed 인증서라고 하고, 제 3의 공인기관(CA: Certificate Authority)에서 인증한 경우 공인 인증서라고 한다.
Self-signed 인증서를 가정해보자.
클라이언트가 서버에 접속하면 서버는 이 인증서를 내려보낸다.
클라이언트는 이 인증서의 서명을 인증서에 있는 공개키로 복호화한다.
클라이언트는 인증서의 서명부분을 제외한 내용을 digest(hash)하여 복호화한 서명과 일치하는지를 확인한다.
일치하면 해당 서버가 서명한 것이 맞는 것이고, 일치하지 않는다면 해당 인증서는 위조된 것이다.
위조된 것이 아니라면 이 다음에는 대칭키로 사용할 어떤 비밀정보를 생성해서 이를 인증서에 포함된 서버의 공개키로 암호화하여 서버로 전송한다.
이 암호화된 비밀정보는 서버의 개인키로만 풀 수 있다.
서버가 개인키로 그 비밀정보를 복호화하면 서버와 클라이언트 모두 대칭키 암호화 키를 갖게 되는 것이고 이후로는 양쪽만 안전하게 통신할 수 있는 비밀통로가 생성되는 것이다.
이렇게하여 대칭키와 비대칭키를 모두 이용하여 빠르고 안전한 통신과 서버의 신원확인을 하게 되었다.
하지만 여기에는 문제가 있다.
인증서에 포함된 서명과 공개키로써 해당 인증서의 내용에 변경이 가해진 것은 아니라는 것은 확인했는데, 그 소유주가 실제 소유주인지는 어떻게 확신할 수 있는가?
즉, 편지가 밀봉이 되어있고, 그 겉에는 홍길동이라고 써져있는 인장이 찍혀있고 전혀 뜯은 흔적이 없는 상황이다. 하지만 그 인장이 정말 홍길동의 인장이라는 확신을 어떻게 할 수 있는가? 홍길동이 아닌 전우치가 그럴듯하게 홍길동인 척 편지를 써서 밀봉을 하고 그럴듯하게 인장을 찍으면 진짜 홍길동 인장을 알지 못하는 사람이 보면 편지에 훼손은 없지만 결국 그 편지가 가짜라는 것은 알 수가 없게 된다. 즉, 이 방식으로는 가짜가 진짜인 척하는 것을 분별할 방법이 없다.
따라서 자기가 자기임을 증명해서는 안되고 홍길동을 확실히 아는 공신력있는 다른 사람이 신원확인을 해줘야 신원이 진짜라는 것을 확신할 수 있는 것이다.
그런 이유로 CA(Certificate Authority)가 필요한 것이고, 자신이 서명을 하는 게 아니라 CA가 서명을 해야 진짜임을 확신할 수 있다.
다시 인증서의 내용을 보자.
인증서에는 서버의 정보 (서버 이름, 소유자 e-mail 등)와 서버의 공개키가 들어있다. 그리고 누가 인증을 했는지를 가리키는 인증자의 정보가 있고, 이런 모든 정보들을 digest(hash)해서 해당 인증자의 개인키로 서명을 하여 인증서에 덧붙여 인증서가 최종 완성된다. 공인 CA가 인증자로서 CA 자신의 개인키로 digest를 암호화하여 서명을 만들고 이게 인증서에 붙으면 공인 인증서가 된다.
브라우저는 공인 CA의 인증서 목록을 갖고 있어서 서버 접속시에 받은 서버 인증서의 서명이 공인 CA가 서명한 것인지 확인할 수가 있다. (다시 말하지만 인증서 안에는 공개키가 들어있다. 즉, CA 인증서 안에는 CA의 공개키가 있으니 CA 개인키로 암호화한 서명을 풀 수 있는 것이다.)
브라우저에 모든 CA 인증서 목록을 다 갖고 있을 수는 없으니 서버의 인증서는 chain으로 누가 서명했는지를 함께 갖고 있을 수 있다. 즉, A <- B <- C <- D 로 서명이 되어있다. (A는 B가 인증하고, B는 C가, C는 D가 인증한 것이다. D가 Root CA이다. ) 브라우저는 B인증서를 갖고 있지 않아도 이렇게 서버 인증서가 chain으로 구성되면 ‘D’ root CA 인증서를 갖고 있는것으로 전체를 인증할 수 있다. (나는 너를 믿지 않지만 너를 믿는 그를 믿기에 너도 믿기로 했다. 뭐 이런 구조다…)
예전 어떤 애니에서 비슷한 말이 있었던 것 같은데… (천원돌파 그렌라간…)
너는 너를 믿지 않지만, 너는 나를 믿지? 나는 너를 믿으니, 너를 믿는 나를 봐서 너도 너를 믿어! 뭐 이런 말이었던 것 같다… 🙂
반대이지만 구조가 비슷한 유행가 가사도 있던 것 같은데… 네가 너를 모르는데, 난들 너를 알겠느냐~~ (딴데로 또 샌다…)
정리하면…
대칭키는 암호화, 복호화 속도가 빠르지만 키 전송의 위험이 있다. (전송할 데이터를 보호하는 키가 필요. 이 키를 전송해서 양쪽이 공유해야하니 이 키를 전송할 때 보호할 또 다른 키가 필요. 이 다른 키도 전송해야하니 또 키가 필요.. 쿨럭…)
비대칭키는 속도는 느리지만 키 전송의 위험을 극복할 수 있다. (공개키는 아무 부담없이 나눠줘도 된다. 공개키로 암호화한 것은 개인키로만 복호화할 수 있다. 개인키로 암호화한 것은 공개키로만 복호화할 수 있다.)
인증서의 목적은 빠르고 안전한 통신과 서버의 신원확인을 하기 위함이다.
인증서안에는 서버의 정보와 서버의 공개키가 들어있고, 이 내용이 위조되지 않았고 변조되지 않았음을 인증기관이 확인하여 서명한다.
공인 인증기관이 아닌 서버 개인키로 스스로 서명한 것은 self-signed 인증서라고 한다.
인증서는 chain으로 구성될 수 있다.
클라이언트가 서버에 접속하면 서버는 서버의 인증서를 내려보내고, 클라이언트(브라우저)는 다운받은 서버 인증서의 서명을 브라우저가 갖고 있는 공인 CA가 한 것인지를 확인하여 공인 인증서인지, self-signed 인증서인지를 확인한다.
대칭 비밀키를 만들어서 인증서에 있는 서버의 공개키로 암호화하여 서버로 보낸다. 이 암호화된 비밀키는 서버의 개인키로만 복호화할 수 있으니 서버와 클라이언트간에만 공유가 된다.
서버와 클라이언트는 이 비밀키로 데이터를 암호화하여 빠르고 안전한 통신을 한다.
openssl을 써서 키 생성, 인증서를 만드는 것은 다음에… (힘들다…)