[기말] 8장 보안
보안(Security)란, '메세지를 송신자와 수신자 두 명만 해석할 수 있도록 하는 것'이다.
중요 개념으로는
- Confidentiality ( 기밀성 )
- Integrity ( 무결성 )
- Authentication ( 인증 )
이 있다.
1. 암호화 방식
암호화의 방식에 대해 설명하기 전에, 주로 사용할 용어에 대해 간단하게 정리하고 가보자.
- Plaintext : 평문, 암호화 되지 않은 상태의 일반 문장을 의미한다.
- Ciphertext : 암호문, Plaintext를 암호화한 문장을 의미한다.
- Encryption key : 암호화 키, 암호화에 사용될 키를 의미한다.
- Decryption key : 복호화 키, 복호화에 사용될 키를 의미한다.
암호화를 통해 우리가 궁극적으로 이루고자 하는 목표는 보안이다.
보안이 필요하다는 것은, 실질적인 공격이 존재함을 의미한다.
지피지기 백전불태라고, 수비를 위해서는 공격 방식에 대해 알아야한다.
먼저, 대표적인 공격 방식은 다음과 같다.
- Eavesdrop : Sniffing이라고도 하는데, 패킷을 도청하는 것이다.
- Insert : Injection이라고도 하는데, 패킷 스트림 사이에 내 데이터를 슬쩍 껴서 보내는 것이다.
- Impersonation : Sniffing을 통해 송수신자의 한 쪽 정보를 알아낸 뒤, 그 사람인 척 하고 통신하는 것이다.
- Hijacking : 잘 가던 패킷을 뺏어서, 결과를 변경하는 것이다. naver를 가다가 tistory로 오게 한다던가...
- Denial of Service : D-DOS라는 방식이 많이 익숙할 것이다. 네트워크가 감당가능한 이상으로 요청을 보내 마비시키는 것이다.
이런 공격들로부터 정보를 지키기 위해, 암호화를 사용하는데 고전적으로 공격자들이 암호화를 뚫는 방법은 이런 것들이 있다.
- Brute force : 경우의수가 1부터 100까지라면 1부터 100을 전부 넣어보는 방식이다.
- Known-plaintext attack : <평문, 암호문>쌍을 알고있을 때, 대입을 통해 암호화 키를 도출하는 방식
- Chosen-plaintext attack : 통신자의 네트워크에 침입해 직접 짧은 평문을 암호화해보고, 이를 통해 키를 도출하는 방식
이제 일반적으로 사용하는 암호화 방식 두가지에 대해 알아보자.
주로 사용하는 암호화 방식은 '대칭키' 암호화 방식과 '공개키'암호화 방식이 있다.
대칭키 방식은 송-수신자가 서로 똑같은 키를 공유하고, 그 키를 통해 암호화/복호화 하는 방법이다.
이 방식의 문제점은, 송-수신자가 똑같은 키를 공유하게 해야한다는 점이다.
공개키 방식은 이를 해결하기 위해 만들어진 방법으로, 소수(Prime)를 이용해 공개키와 개인키를 만드는 방식이다.
공개키로 암호화 한것은 개인키로 복호화 가능하고, 그 반대의 경우도 가능하다.
일단 먼저 대칭키(Symmetric Key)에 대해 알아보자.
대칭키는 치환 암호(Substitution Cipher)를 사용한다.
예를 들어 A->G, B->E... 뭐 이런식으로 변환하는 테이블이 있고, 이것을 활용해 메세지를 암호화 한다.
하지만 이제 단순히 이것만 하면 보안이 너무 약할테니까, 이것을 좀 더 고도화한 여러 방법이 있다.
먼저 DES(Data Encryption Standard), 1993년에 등록된 표준이다.
평문을 64비트 단위로 쪼갠 뒤, 56비트의 암호화 키를 이용해 블록 단위로 암호화하는 방법이다.
방법을 보면 뭐 64비트 값을 반으로 쪼개고, 각각을 암호화하고, 두 결과를 XOR하고.. 이걸 몇번 반복하고..
이렇게 복잡한 작업을 거치는데, Brute-force 방법을 사용해도 하루만에 뚫리는 처참한 방어력을 가졌다.
이를 해결하기 위해 DES의 결과를 다시 DES하고 또 DES하는 3DES같은 방법도 존재하지만 약한건 마찬가지였다.
그래서 새롭게 나온 방식이 AES(Advanced Encryption Standard), 2001년에 등록된 표준이다.
이 방식은 블록이 128비트 단위고, 암호화 키는 128비트, 192비트, 256비트의 3종류가 존재한다.
DES로 암호화했을 때 1초면 뚫을 수 있는 것은 AES에서는 약 149조년이 걸린다고 한다.
미국 정부가 기밀 문서를 암호화할때도 이 방식을 채택했다고 하니 그 안전성은 높을 것이다.
하지만 결국 통신과정에서 대칭키 방식을 쓸려면 가장 큰 문제가 있다.
통신자가 서로 같은 대칭키를 가지고 있어야 한다는 것인데,
이 대칭키를 그냥 전송해버리면 공격자가 그냥 낼름 먹어버리면 바로 해독이 가능해져 버릴테니..
물론 이를 해결하는 방법도 존재하는데, 이것이 공개키 방식이다.
공개키의 표준같은 방식은 RSA인데, 이름은 개발자들의 성을 따서 붙인 방식이라 약어는 아니고, 약 1977년에 개발됐다.
공개키 방식에서는 모두에게 공개되는 공개키와 자신만 가질 수 있는 개인키가 있다. 여기서,
- 공개키로 암호화 한것을 개인키로 복호화 할 수 있어야 하고, 그 반대도 가능해야 한다.
- 공개키를 이용해 개인키를 추정할 수 없어야 한다.
는 두 가지 조건을 만족해야 하고, 이를 해결하기 위해 Prime number와 Modulo Operation을 사용한다.
[공개키 / 개인키 생성 방식]
1. 먼저 매우 큰 소수 P, Q를 선택한다. (RSA-2048에서는 2048비트의 소수를 선택)
2. N = P*Q, Z = (P-1)(Q-1) 이다.
3. E는 N보다 작으면서 Z로 나누어 떨어지지 않는 수다.
4. D는 (E*D)-1을 Z로 나누어 떨어지게 할 수 있는 수다.
이 과정을 마치고, 공개키는 (N, E), 개인키는 (N, D)가 된다.
암호화를 할 때에는 {(message bit)^E} mod N 연산을 수행하고
복호화를 할 때에는 {(cipher bit)^D} mod N 연산을 수행한다.
율러 법칙에 따라 반대의 경우도 가능함이 증명된다.
공개키/개인키 방식을 뚫는게 어려운 이유는 N을 소수 P,Q의 곱으로 나타내야하는데,
P,Q가 각각 2048비트이기 때문에 그것을 찾는 연산을 하는데 아주 긴 시간이 걸린다.
( 프로그래밍에서 주로 쓰는 int는 32비트, long은 64비트..., 게다가 N은 2048비트 2개를 곱한 것... )
그러나, 대칭키 방식과 달리 연산 속도만 받쳐주면 뚫을 수 있다는 이야기이기도 하다.
그래서 양자컴퓨터가 등장하면 RSA가 위험해 질 것이라는 추측이 많다.
아무튼, 설명에서 봤듯이 공개키/개인키는 아주 큰 수로 Pow연산을 하고 Mod 연산을 하는 방식이다.
그렇기 때문에 연산의 비용이 꽤 비싼편에 속하므로, 통신의 모든 메세지를 공개키/개인키를 통해 암호화 했다가는
암호화하고 복호화 하는 시간이 너무 길어져 버릴 것이다.
그래서, 일반적으로 공개키/개인키는 대칭키를 암호화해서 보낼 때 사용하고, 이후 통신은 대칭키 암호화로 수행한다.
2. 인증
메세지를 암호화하고 복호화하는 과정에 대해서는 어느정도 이해했다.
하지만, 메세지를 암호화하고 복호화하는 것만으로 공격으로부터 안전할까? 그건 아닐것이다.
한 번 메세지 전달 프로토콜의 발전 과정을 따라가보자.
[Authentication Protocol 1.0]
A가 B에게 메시지 평문을 그대로 보낸다.
-> 공격자도 B에게 메시지 평문을 그대로 보내면, B는 그 메세지가 A부터 왔는지 공격자로부터 왔는지 알 수 없다.
[Authentication Protocol 2.0]
A가 메세지 헤더에 자신의 IP Address를 넣어서 메시지를 보낸다.
-> 공격자는 메시지를 Sniffing해서 IP Address를 알아낸 뒤, 자신의 메세지 헤더에 그 IP Address를 넣는다.
-> B는 역시 그 메시지가 A부터 온 것인지 공격자로부터 온 것인지 알 수 없다.
[Authentication Protocol 3.0]
A가 메세지 헤더에 자신의 IP Address와 자신임을 증명하는 암호를 넣어서 보낸다.
-> 공격자는 메시지를 Sniffing해서 그 헤더를 그대로 떼서 자신의 메시지에 붙여서 보낸다.
-> B는 역시 구분할 수 없다.
이런 방식은 Playback Attack 혹은 Replay Attack이라고 하는데 A가 수행했던 내용을 공격자가 패킷 복사를 통해 그대로 따라할 수 있다는 점에서 굉장히 위험한 취약점이다.
[Authentication Protocol 4.0]
Playback attack을 피하기 위해, 세션 주기에 단 한 번만 사용하는 Nonce라는 값을 만들어서 사용한다.
A가 B에게 메시지를 보내면, B는 A에게 Nonce를 보내고, A는 이 Nonce를 대칭키로 암호화해서 B로 보낸다.
그러면, B는 암호화된 Nonce를 복호화해서 올바르게 온 데이터임을 확신할 수 있다.
만약 이미 사용된 Nonce에 대해 추가 패킷이 오면, 공격이라고 생각하면 된다.
[Authentication Protocol 5.0]
그러나 4.0에서는 결국 Nonce를 대칭키를 이용해 암호화 하고 있는데, 이를 공개키로 암호화 하는 방식은 없을까?
A가 B에게 메시지를 보내면, B는 A에게 Nonce를 보내고, A는 이 Nonce를 개인키로 암호화 해서 B로 보낸다.
B는 A에게 공개키를 요청하고, A는 B에게 공개키를 보내고, B는 A의 공개키를 이용해 암호화된 Nonce를 검증한다.
와 같은 방식으로 수행할 수 있다.
하지만, 이 경우 Man-in-the-middle attack 이라고 하는 공격 ( 제 3자 사기라고 하면 이해가 편할 듯 하다 )에 당할 수 있다.
예를 들어, A와 공격자가 통신하고, 공격자와 B가 통신하면서 사이에서 데이터를 다 읽어버릴 수 있다.
이런 문제점을 해결하기 위해 인증(Message Authentication)가 필요하다.
내가 지금 받은 공개키가 정말 A의 공개키가 맞을까? 공격자의 공개키가 아닐까? 라는 의문을 해결하기 위해
공인인증서같은 느낌의 CA (Certification Authorites)가 생겼다.
자신의 공개키를 자신이 누군지(Person, Website, Router...)와 같이 CA에 등록하면,
CA는 내 공개키를 CA의 개인키로 암호화해서 돌려준다. (CA-(K+))
CA의 공개키는 공개되어있으므로, 수신자는 CA-(K+)를 CA+로 복호화해서 내 공개키를 얻을 수 있다.
3. 메세지 무결성, 기밀성
이제 우리는 메세지를 보낸 사람이 누군지를 인증할 수 있게 됬다.
그렇다면 마지막으로, 메세지가 전송되는 과정에 누가 내용에 뭔가를 추가하거나 변경하지 않았는지를 검사해야하고,
중간에 공격자가 이 메세지의 내용을 도청할 수 없게 해야한다.
먼저, 메세지의 무결성을 위해서는 Hash Function을 사용한다.
Hash의 특성에 대해 짧게 설명하자면, "복호화가 안되고, 각 입력에 대해 Unique한 출력"을 만드는 함수다. 또한, 함수에 따라 Hash의 길이가 고정되기도 한다.
아무튼, 메세지 원문과 Hash(M)을 같이 보내면 수신자는 메세지 원문의 Hash를 계산해서 Hash(M)과 비교하여 메세지가 수정되었는가를 확인할 수 있을 것이다.
(단, Hash(M)을 복호화 할 수 없으므로, Hash(M)만 보내는 방식은 불가능하다.)
무결성은 해결했지만, 이러면 기밀성은 어떻게 해야할까? 암호화 하면된다.
(M, Hash(M))을 대칭키 Ks를 이용해 암호화한다. Ks(M, Hash(M))
그리고, 대칭키 Ks는 CA를 통해 얻은 수신자의 공개키를 이용해 암호화 해서 같이 보낸다.
그렇다면 최종 메세지 패킷은 다음과 같은 구조가 될 것이다.
메세지 원문(M) --------ㄱ=> 발신자의 개인키로 암호화 => 대칭키로 암호화-ㄱ
메세지 해시(Hash(M)) ---」 |
├-----> 전송
대칭키 Ks를 수신자의 공개키로 암호화 ------------------------------------」
그러면 수신자는 어떻게 메세지를 얻어낼까?
1. 자신의 개인키를 이용해 대칭키 Ks를 얻는다.
2. 대칭키 Ks를 이용해 복호화한다. => 메세지의 기밀성 보장
3. CA를 이용해 발신자의 공개키를 얻어 복호화 한다. => 발신자가 올바른지 인증
4. 찾아낸 M의 Hash를 계산해 Hash(M)과 비교한다. => 메세지의 무결성 보장
5. 같다면 메세지가 안전하게 잘 도착한 것이다.
와! 우리는 이제 원하는 사람한테서 다른사람에게 보이지 않고 수정되지 않는 메세지를 받을 수 있게 됬다!
4. TLS ( Transport Layer Security )
위에서 인증과정에 대해 충분히 살펴봤는데, 그렇다면 이 인증과정을 직접 수행해야할까? 그건 아닐 것이다.
일반적으로 OSI 계층으로 볼 때, 우리는 주로 Application Layer를 다루고, 이런 과정은 Presentation Layer에서 진행된다.
하지만, 어떻게 돌아가는지에 대해서 한 번 알아보자.
먼저, A와 B의 연결과정. Hadnshake에서 Secret key를 공유한다. ( Secret Key를 이용해 key를 만든다 )
1. A - [연결 요청] -> B
2. A <- [CA(B의 공개키)] - B
- A는 CA키를 복호화해서 B의 공개 키를 얻는다.
3. A - [B+(Secret Key)] -> B
- A는 Secret key를 B의 공개키로 암호화해서 B로 보낸다.
이 과정을 통해, A와 B가 Secret Key를 공유하게 된다.
그 다음으로, Secret key를 이용해 각자 키를 만들어 공유한다. ( Key derivation )
- Encryption Key : 암호화를 위한 Key
- MAC : Message Authentication Code, 메세지를 인증하기 위해 뒤에 붙이는 코드
이렇게 키를 모두 만들고 나면 데이터 통신을 진행하는데, TCP의 Stream을 잘라 Record 단위로 만든다. ( Data transfer )
그 이유는, 메세지의 인증을 위해 MAC를 뒤에 붙여야하는데,
Stream 상태로 진행을 하면 모든 메시지의 끝에 MAC이 붙게된다.
그러면 메세지를 전부 수신한 다음에야 인증이 가능하므로, 한 Cycle에 너무 긴 시간이 들어가게 된다.
그래서 Stream을 자른 data 뒤에 MAC을 붙이는데, 어디부터 어디까지가 data고 MAC인지 구분이 안된다.
이를 구분하기 위해, data의 길이를 알려주는 length를 헤더에 넣게 된다.
Record : {[Data Length] - [Data] - [MAC]}
근데 그냥 이렇게만 보내면, 공격자가 Record를 복제해서 보내거나 중간에 빼내서 순서를 뒤죽박죽 섞어서 보낼수 있다.
이 문제를 해결하기 위해, MAC 데이터 쪽에 Sequence # 값을 넣어 Record의 순서를 지정한다.
또 위에서 봤던 Replay attack을 막기 위해 Nonce data도 같이 넣게 된다.
이제 메세지 송수신은 어떻게 된 것 같은데, 공격자가 TCP FIN을 보내버릴수도 있다. ( Connection Closure )
그러면 데이터가 아직 다 도착안했는데 '끝인가?'하고 수신 종료 해버리게 만들어버리는 것인데,
이를 해결하기 위해 Record에 이게 마지막 레코드다 라는 데이터를 넣고,
그 데이터가 도착하기 전에는 TCP FIN을 무시하게 만들 수 있다.
그래서 TLS에는 이런 키 생성, 암호화, MAC, 디지털 서명 등에 대한 알고리즘 타입을 정할 수 있게 하는 Cipher suite가 존재한다. 2008년에 발표된 TLS 1.2에서는 이 Cipher suite가 37가지 존재 했으나, 2018년 발표된 TLS 1.3에서는 안정화된 5가지의 알고리즘으로 축소하게 되었다.
예를 들어, 과거의 대칭키 Cipher suite는 DES, 3DES, RC2, RC4등이 있었으나 현재는 RSA만 사용된다.
통신 양방이 이 Cipher suite를 협상하는 과정은 Handshake과정에서 진행된다.
5. IPSec (Internet Protocol Security)
위에서의 SSL, TSL은 TCP의 Stream에 대한 내용이었다면, IPSec은 그보다 더 Low-Level이라고도 할 수 있는 Datagram의 암호화, 인증, 무결성을 위한 보안절차다.
IPSec에는 두 가지 모드가 있는데
1. 헤더를 제외하고 Payload만 암호화하는 Transport mode
2. 헤더와 Payload를 모두 암호화하는 Tunnel mode
가 있다.
IPSec을 위한 프로토콜도 대표적인 두가지가 있는데
1. AH (Authentication Header) Protocol
2. ESP (Encapsulation Security Protocol )
이다.
두 프로토콜은 모두 데이터의 인증, 무결성에 대해 수행하지만, 기밀성에 대해서는 ESP만 수행하므로 주로 사용되는 쪽은 ESP다.
IPSec은 데이터 통신 전, Sender와 Receiver간 단방향 SA(Security Association)를 2개 설치하게 된다. ( 방향마다 )
IP/UDP는 Connection-less로 통신하는 것과 달리, IPSec는 Connection으로 검증하는 것을 볼 수 있다.
각 End-point는 SA의 상태 정보를 유지하게 된다.
- SPI (Security Parameter Index), 시작점과 종료점의 IP, 암호화, 무결성 검증 방법, 암호화 키, 인증 키 등...
IPSec Datagram은 다음과 같다.
[New IP Header - (ESP Header - {Original IP Header - Original Datagram Payload - ESP Trailer} - ESP Auth(MAC))]
ESP Header : [SPI, Sequence #]
ESP Trailer : [Padding, Pad length, Next Header]
{ } 로 감싸진 부분은 암호화되는 부분이고,
( ) 로 감싸진 부분은 인증에 사용되는 부분이다.
IPSec의 수행과정은 IKE(Internet Key Exchange), PSK(Pre-shared Secret Key), PKI (Public Key Infrastructure) 등이 있다.