암호화 (Encryption) 과 전자 서명 (Digital Signature) 은 범용적으로 사용되는 기술이고, 저는 API 통신을 설계하며 접할 수 있었습니다.
이 두가지는 유사한 맥락에서 사용되거나 동시에 사용되는 경우가 있고, 전혀 다른 목적과 특징을 지니고있기때문에 잘 구분하고 있어야합니다.
이 두가지 행위를 간단한 방식으로 처리할 수 있도록 저를 도와줬던 기술이 비대칭키 알고리즘이었기에, 이번 글에서는 비대칭키와 연관지어 이 두 요구조건에 대해 적어보려고 합니다.
비대칭키 알고리즘은 특정 요구조건을 만족시키 위해 쌍을 이루는 공개키와 비공개키로 암호화 및 복호화를 수행하는 기술입니다.
전자 서명 또는 인증은 공개키와 비공개키 두개를 운용할때 발생하는 구조와 맥락을 이해하면 자연스럽게 파악할 수 있습니다.
비대칭 키는 공개키와 비공개키로 암호화와 복호화를 수행하는 것이라고 위에서 언급했습니다.
이 비대칭성을 아래와 같이 추상화해 보았습니다.
[구조]
- 평문을 공개키로 암호화 할 때에는 비공개키로 복호화 할 수 있다
- 평문을 비공개키로 암호화할 때에는 공개키로 복호화 할 수 있다
[맥락]
- 공개키는 누구나 열람할 수 있다
- 비공개키는 혼자만 지녀야하고 유출 되어서는 안된다
위 구조에 따라 설계될 수 있는 두가지 케이스를 살펴보겠습니다.
이 두가지 구조는 논리적으로 살펴볼 필요가 있습니다.
유사한 구조로 통신을 하는 것 같지만, 목적이 전혀 다른 설계입니다. 제가 서두에서 "유사한 맥락"이라고 언급했던 이유입니다
결론부터 말하자면 전자는 인증 (Authenticate) 과 전자 서명 (Digital Sign) 을 하고있고, 후자는 암호화 (Encrypt) 를 하고있습니다.
왜 그러한지는 위에서 언급한 구조와 맥락을 논리적으로 생각해보면 자연스럽게 이해할 수 있습니다.
주목할 점은 공개키는 누구나 열람할 수 있다는 점입니다.
예시로 아래 링크에서 애플 OAuth 인증 시 사용하는 공개키들을 확인할 수 있습니다.
https://appleid.apple.com/auth/keys
receiver 은 쉽게 sender 의 공개키를 가질 수 있습니다. 모두에게 공개되어있기 때문이죠.
그에 반해 비공개키는 sender 만 가질 수 있습니다. (그래서 개인키라고도 부릅니다)
비대칭키 특성에 의해, 어떤 데이터가 공개키로 복호화가 된다면, 그 데이터는 무조건 쌍을 이루는 비공개키로 암호화 되었음을 의미합니다.
즉, 논리적으로 그 데이터가 보낸 sender 를 특정지을 수 있습니다.
저는 A 의 공개키를 가지고 있고, 어떤 데이터 X 가 A 의 공개키로 복호화에 성공했다면, 그 데이터는 A 가 보냈음이 확실합니다. 왜냐하면 쌍을 이루는 비공개키는 A 만 가지고 있기 때문입니다.
"sender 가 누군지 특징지을 수 있다"
이것은 사전적 의미로 인증 Authenticate 를 뜻 합니다. 따라서 비공개키로 암호화하는 행위를 하는 것 만으로, 저희는 인증을 수행할 수 있습니다.
다만, 데이터 X 는 전세계 사람들이 열람할 수 있습니다. 공개키만 있으면 복호화가 가능하기 때문이죠.
따라서 비공개키로 암호화하는 데이터는 기밀성이 지켜지지는 않습니다. 그래서 인증된 사용자로 부터 공개된 데이터를 받을 때 요긴하게 사용됩니다.
아직 전자서명에 대한 이야기는 꺼내지 않았습니다. 전자서명은 이러한 비공개키 암호화 방식을 한 단계 더 활용한 기술입니다.
전자서명은 수많은 곳에서 활약하고 있지만, JWT (JSON WEB TOKEN) 를 보면 근본적인 동작 방식을 이해하기 쉽습니다.
( Encoding 의 개념은 이번 포스팅과 연관이 없으므로 제외하고 설명하겠습니다 )
JWT 는 payload 에 데이터를 담아서 "정보를 전달" 함과 동시에 "인증" 의 기능을 수행합니다.
아래와 같은 세가지 정보를 담고있는 것을 다들 아실겁니다.
여기서 PAYLOAD 에 정보가 담기는데, 이는 암호화되지 않았습니다. 해당 토큰을 탈취한다면 누구나 내용을 확인할 수 있습니다.
해당 데이터를 위조하거나 변조하는것이 매우 쉽습니다. 아무런 암호화를 하지 않고 있기 때문입니다.
그래서 위변조를 막기 위해 SIGNATURE 이라는 섹션이 존재합니다.
HEADER 와 PAYLOAD 의 정보들을 sender 가 비밀키로 해싱하여 암호화된 값 (해시값) 을 만들어 냅니다. 따라서 비밀키를 가지고 있지 않으면 올바른 시그니처를 만들 수 없습니다.
이때 사용하는 해시 알고리즘은 HMAC 알고리즘입니다. 비밀키를 사용한다는 점이 특징입니다.
이 동작을 일반적으로 암호화라고 부르지는 않고 비밀키로 해시값을 생성한다고 합니다. 왜냐하면 해싱은 복호화를 염두하지 않기 때문입니다. (해시값 그 자체로 임무를 수행하기 때문)
하지만 비밀키와 알고리즘의 조합을 통해 값을 만들어 내기에 암호화라고 표현하였습니다.
따라서 sender 가 토큰에 서명 (signature) 을 추가하면, jwt 가 올바르지 않은 서명을 가지고 있음을 공개키로 receiver 가 확인할 수 있기 때문에 토큰이 위변조 되는 것을 막을 수 있습니다.
비밀키로 암호화 하는 경우를 분석해 보았습니다. 자연스럽게 아래와 같은 특징이 있음을 이해할 수 있습니다.
그럼 공개키로 암호화하는 건 어떤 경우일까요?
이 경우 누구나 공개키를 갖고있기 때문에 receiver 에게 암호화된 데이터를 보낼 수 있습니다.
데이터를 보낸 사람이 해커인지 여자친구인지 알 수 없습니다. sender 를 추측하는데에는 도움이 되지 않습니다.
다만, 비밀키는 저 혼자 갖고있기 때문에 전달받은 데이터의 내용은 오로지 저만 확인할 수 있습니다.
그렇기 때문에 기밀성이 유지됩니다.
예를들어 sender 가 유저의 패스워드를 제게 보내려고 할때, 공개키로 암호화 할 경우, 그 데이터가 해커에게 탈취되어도 해커는 비밀번호를 특정지을 수 없습니다. 비밀키는 저만 갖고있기 때문이죠.
따라서, receiver 는 공개키/비밀키 쌍을 생성하고, 공개키를 API 로 열어두면, 암호화된 데이터를 누군가 전송하려고 할때 저의 공개키로 암호화하여 보내게 처리해줍니다.
애플이 아래와 같이 공개키를 API 로 열어둔 의미를 파악할 수 있습니다.
https://appleid.apple.com/auth/keys
애플로그인을 구현해본 사람이라면, 이 키를 fetch 해와서 user 를 validate 했던 경험이 있을겁니다.
또는 ssh 통신할때도 RSA 등의 알고리즘으로 비대칭키를 생성하여 공개키를 제공했던 경험도 있으실겁니다. 예를 들면 깃헙에 키를 등록해두고, ssh 기반 인증을 통해 Push, Pull 등을 할 수 있었던 것 처럼요!
아무튼 유사한 맥락으로 보이지만, 어떤 키로 암호화를 하냐에 따라 매우 다른 목적과 동작을 합니다.
대칭키 인증방식보다 좀 더 활용 반경이 넓은것을 느낄 수 있습니다.
또한 사용하면서 비대칭키 인증방식이 대칭키 인증방식보다 더 좋다고 느꼈던 부분이 있는데, 보안 책임을 전가할 수 있다는 점입니다.
비대칭키와는 다르게 대칭키는 sender 와 receiver 둘 다 가지고 있는 상태로, 동일한 키로 암호화 및 복호화를 처리하며 여러 요구조건을 충족시킵니다.
다만 sender, receiver 두 곳에서 이 키를 안전하게 지킬 필요가 있습니다.
이 통신이 단순히 저와 제 친구가 주고받는 통신이라면 서로에게 주의를 주며 조심할 수 있겠지만,
누군가에게 서비스를 제공하는 입장에서 (예를들면 OAuth 인증), 어떤 추상적인 집단과 대칭키를 공유한다는 것은 큰 부담입니다.
저희가 구글로그인을 대칭키 방식으로 진행한다면, 저희 서비스가 보안적으로 털리는 경우, 구글 유저들에게 큰 피해를 끼칠 수 있습니다.
하지만 구글로그인을 비대칭키 방식으로 진행하고 저희는 구글이 만들어준 공개키만 이용한다면, 저희 서비스가 보안적으로 털려도 구글에는 아무런 피해가 없습니다. 공개키는 애초에 누구나 열람할 수 있기 때문입니다.
회사 프로젝트에서도 이러한 장점을 적극 인정하고, 서버 간의 통신에서 비대칭키 인증을 사용하고 있습니다.
보안 주체가 비대칭키를 만들어 공개키 JWKS 를 API 로 제공하고, 공개키로 Signing 된 JWT 를 이용하여 인증을 진행한다거나, 또는 탈취되어서는 안되는 데이터를 공개키로 암호화해서 주기도 합니다.
이렇듯 비대칭키 개념을 이해하는 과정은 서비스를 만드는 과정에서 제게 다양한 유용한 방식들을 제공해주었습니다.
이 글을 읽는 분들도 분명 인증에 대한 고민들을 많이 하실텐데, 조금이라도 도움이 되었으면 좋겠습니다.
어떠한 서비스를 만들때, 이 방식은 논리적으로 보안이 안전함 을 검증하는 과정은 꽤나 재미있는 것 같습니다.
내용에 대한 피드백이나 질문 댓글은 언제나 환영합니다! : )