Spectre Variant 2 공격 원리분석과 대응방안에 대한 제언
공격조건 까다로운 만큼 한 조건만 잘 막아도 방어 가능해
사실 Spectre Variant 2는 이 세 가지 유형 중에서도 매우 특별한 형태다. 공격을 위한 코드가 극단적으로 복잡하고 어려운 기술을 사용한다는 점이 첫 번째고, 세 가지 중 유일하게 VM escape이 가능한 취약점이라는 것이 두 번째다. 다시 말해 이 취약점이 패치되지 않는다면 guest VM에서 host kernel 또는 다른 guest VM의 메모리를 읽을 수 있는 가능성이 존재하게 된다.
물론 앞서 설명한대로 공격방식이 매우 복잡하기 때문에 공격을 성공시키기 위한 준비 작업부터 아주 까다롭다. 구글의 PoC 코드에서는 KVM host가 hypervisor의 메모리를 초당 1500바이트씩 읽을 수 있었는데 이 작업을 위해 10~30분의 초기화 과정이 필요했을 정도다. 더불어 이 취약점은 인텔계열 CPU에만 국한되는 것이 아니기 때문에 AMD CPU, ARM, 모든 종류의 현세대 CPU가 공격대상이 된다는 점에서 심각성이 더하다. 당연히 짐작하겠지만 guest VM이 host kernel을 공격할 수 있다는 건 일반 어플리케이션이 커널을 공격하는 일도 가능하다는 뜻이다.
Indirect Branch Target Injection
이 취약점에 대해 설명하려면 이에 앞서 분기예측에 대한 상세한 설명이 필요하다. 여기서 Branch Target이라는 것은 분기의 목적지인데, 이 경우 공격대상이 되는 것은 좀 더 정확하게 말하면 간접분기 목적지(Indirect Branch Target)이다. 직접분기는 분기의 목적지를 명시적으로 표시하지만, 간접분기에서는 레지스터나 메모리의 내용을 통해 간접적으로 목적지를 지정한다. 말하자면 다음과 같다.
메모리 A의 주소로 분기한다(직접분기) : 컴파일타임에 분기주소를 알 수 있다.
메모리 A의 값이 가리키는 주소로 분기한다(간접분기) : 컴파일타임에는 분기주소를 알 수 없고, 런타임에만 알 수 있다.
직접분기의 경우는 어디로 분기한다라는 주소가 명확하므로 추측실행이나 분기예측이 상대적으로 쉽다. 어떤 주소로 이동하는지 그렇지 않은지만 판단하면 되기 때문이다. 하지만 간접분기의 경우는 값이 들어 있는 주소를 보고 그로부터 분기해야 하므로 훨씬 예측이 어려워진다. 아니 어렵다는 얘기 전에, ‘어떤 값이 들어 있는지 모르는데 그런 분기를 예측한다니 이게 가능한 일인가?’라는 생각이 들 수도 있는데 실제로 가능하다. 게다가 상당히 높은 효율을 보여주기 때문에 작금의 CPU들에 있어서 간접분기예측은 성능 향상 차원에서 아주 중요한 기능 중 하나다. 작업에 따라 다르지만 어떤 상황에서는 90% 이상의 적중률을 보여주기도 한다. 특히 현대적인 개발언어들은 모두 객체지향적 특징을 포함하고 있는데 객체지향에서 반드시 필요한 속성 중 하나인 상속의 가상함수 테이블을 구현할 때 이 간접분기를 사용한다. 그렇기 때문에 현대적인 방법으로 개발된 애플리케이션일수록 이 간접분기예측으로부터 이익을 얻을 가능성이 높아진다.
다시 간접분기 주제로 돌아와 보자. 간접분기는 BTB(Branch Target Buffer)라는 것을 사용해 예측한다. 이 구조체는 하나의 코어를 사용하는 애플리케이션 간에는 공유되며 분기점의 주소, 태그, 분기하는 주소를 저장하는 일종의 룩업 테이블이다. CPU는 분기예측을 할 때 BTB를 찾아보고 만약 현재 분기의 주소가 테이블에 있다면 이전에 이 주소에서 어떤 곳으로 분기했는지 알 수 있다. 만약 이 주소에서의 분기가 항상 특정한 목적지로 간다면 이번 분기에서도 그렇게 될 가능성이 높다고 판단할 수 있고, 그 경우는 해당 목적지로 분기하는 추측실행을 하는 것이 가장 이익이 되는 결정일 것이다. 간접분기예측도 마찬가지로, BTB에서 분기점의 주소를 찾고 여기서 어디로 가장 많이 분기했는지를 확인하면 추측실행 시 실행할 코드의 주소를 확인할 수 있게 되는 것이다.
문제는 BTB에서 분기하는 주소는 전체를 사용하지만, 분기점의 주소는 전체를 기록하지 않고 일부만을 저장한다는 점이다. 구현은 CPU에 따라 조금씩 다르지만 구글의 논문에 따르면 여기서 테스트했던 인텔 하스웰 CPU는 주소의 마지막 31비트만을 인덱스로 사용한다. 사실 31비트만 사용하더라도 분기점의 인덱스가 겹칠 확률은 20억분의 1로 대단히 낮아서 실제 수행 시에는 아무런 문제가 없다. 하지만 정교하게 조작한 코드를 통해 공격대상이 되는 분기점 주소와 마지막 31비트가 동일한 다른 분기점 주소가 있다면 CPU는 이를 구분할 수 없게 된다. 그리고 동일한 코어를 사용하는 애플리케이션들 간에 BTB는 공유된다. 즉 한 프로세스의 간접분기결과는 다른 프로세스의 간접분기예측에 영향을 미칠 수 있다는 것이다. 코어를 공유하기만 한다면 해당 프로세스가 무엇이든 상관이 없다. 따라서 하나의 OS에서 운영되는 두개의 다른 프로세스 간, hypervisor에서 운영되는 두 개의 guest VM간에도 영향을 줄 수 있으며, 구글의 PoC에서 확인한 대로 guest VM이 hypervisor의 간접분기예측에 간섭하는 일도 가능해지는 것이다.
위 그림은 CPU가 jmp1과 jmp2의 분기점 주소를 구분할 수 없다는 걸 보여준다. [출처=EVTYUSHKIN, D., PONOMAREV, D. V., AND ABUGHAZALEH, N. B. Jump over ASLR: attacking branch predictors to bypass ASLR. In MICRO (2016), IEEE Computer Society, pp. 1–13]
Spectre Variant 2의 공격구조
Spectre Variant 2는 이런 간접분기예측의 구조에 착안한 것으로, 공격을 하기 위해서는 가장 먼저 대상이 되는 프로세스 내에서 공격에 사용할 수 있는 코드조각을 찾아야 한다. Spectre Variant 1에서 설명한 대로 이를 gadget이라 하며, 프로세스에 따라 사용하는 gadget은 달라질 것이고 어떤 경우에는 적절한 것을 찾지 못할 수도 있다. 또한 Spectre Variant 1는 공격대상인 조건분기문의 다음에 나오는 코드가 바로 gadget이 되어야 하므로 적절한 것을 찾기 어렵지만 Spectre Variant 2는 간접분기주소를 마음대로 지정하여 공격할 수 있으므로 공격대상의 주소공간 안에 있는 어떤 바이트스트림도 조건에 맞는다면 사용할 수 있다. 공격방식은 다르지만 해커들이 침해목적으로 이런 gadget을 사용해온 지는 이미 오래됐기 때문에 이런 작업을 사람이 일일이 하게 되지는 않고 프로세스 공간을 검색하여 어떤 특정한 목적에 맞는 gadget들을 찾아주는 도구들이 이미 나와 있다. 따라서 실제 공격 시에는 이런 도구들을 사용하여 시간을 단축하게 된다. gadget 없이는 당연히 공격을 할 수 없기 때문에 여러 가지 방법을 동원해 gadget이 될 수 있는 코드를 찾아내는 것이 중요하다. 구글의 논문에 나온 예를 들자면 Windows 8과 Windows 10의 ntdll.dll에는 다음과 같은 gadget이 존재한다. 이 바이트스트림이 원래 어떤 목적으로 사용되는지는 중요하지 않다.
13 BC 13 BD 13 BE 13
12 17
이 gadget은 어셈블리로 쓰면 다음과 같은 코드가 된다.
adc edi,dword ptr [ebx+edx+13BE13BDh] adc dl,byte ptr [edi]
이 gadget은 레지스터 edi에 ebx+edx+13BE13BDh이 가리키는 주소의 값을 더하고, 그 후 바로 바로 레지스터 edi가 가리키는 주소의 1바이트 값을 dl에 더하는 매우 간단한 코드이다. 이 gadget을 실행시키기 전에 레지스터 edi, ebx, edx를 모두 조작할 필요가 있는데 일단 ebx와 edx에 다음과 같은 값들을 사용했다고 가정하자. 여기서 m은 읽기를 원하는 공격대상 메모리의 주소이다.
ebx = m – 0x13BE13BD – edx
edx = 3
레지스터 값을 이렇게 설정했다면 첫 번째 연산은 m–0x13BE13BD–3+3+0x13BE13BD=m, 즉 메모리 주소 m에서 32bit 값을 읽어서 edi에 더하게 된다. 두 번째 연산에서는 계산된 edi의 값에 해당하는 주소에서 1바이트를 읽어서 dl에 더하는데 dl 레지스터 자체는 아무런 의미도 없다. 여기서 중요한 것은 이 주소로부터 데이터를 읽었으므로 이 데이터가 캐쉬에 올라가 있을 것이라는 점이다. 또한 애플리케이션 간 공유되는 DLL은 하나만 메모리에 로드되며, 이 DLL이 사용하는 가상메모리 주소는 모든 애플리케이션에서 동일하다. 따라서 DLL에서 쓰는 메모리 영역을 통해 서로 다른 프로세스 간에 데이터를 공유하는 일이 가능한데 만약 edi에 해당하는 주소가 이 영역에 존재한다면 공격자 프로세스가 이 주소를 읽을 수 있다. 그리고 m에서 읽은 값 x에 따라 edi+x에 해당하는 주소가 캐쉬에 올라와 있을 것이므로 앞서와 같은 Side Channel Attack으로 대상의 메모리값을 확인하면 된다. 실제로는 캐쉬라인이 있으므로 edi를 적절하게 증가시켜가면서 반복 테스트해 정확한 값을 얻어야 할 것이다. 만약 리눅스에서라면 DLL이 아니라 shared library를 사용해 같은 공격을 구현할 수 있다.
실제 Spectre Variant2를 이용해 공격을 할 때는, 가장 먼저 조작을 통해 공격대상의 분기점 주소와 마지막 31비트가 동일한 주소를 하나 선택해 여기에 간접분기점을 둔다. 그리고 해당 간접분기점에서 공격자가 실행하고 싶은 코드(즉 gadget)로 계속 분기하도록 실행을 반복해 학습한다. 그 후 공격대상이 실제 분기점에서 추측실행을 통해 분기 목적지의 코드를 실행하려고 할 때는 BTB의 내용에 근거해 gadget이 실행돼야 한다고 추측하게 만드는 것이다. 물론 이 경우는 올바른 추측이 아니므로 바로 파이프라인은 비워지고 실행은 취소된다. 하지만 위의 예에서 보았듯이 gadget이 공격대상의 메모리를 읽고 이를 캐쉬라인에 남긴다면 실행이 취소될지라도 앞서의 공격과 마찬가지로 캐쉬와 일반 메모리 접근 속도차에 의해 정보를 읽어낼 수 있다. 앞서 언급한 대로 CPU는 어떤 어플리케이션이 BTB를 사용하는지 알 수 없다. 따라서 같은 코어를 쓰는 애플리케이션 두 개를 띄워서 한쪽에서 다른 쪽의 간접분기시 gadget을 실행하도록 학습시키는 형태의 공격이 가능해지는 것이다.
Spectre Variant 2의 대응
이 취약점에 대해서는 구글이 retpoline이라는 방법을 제시한 바 있는데, 이는 특정 주소로 간접분기할 때 주어진 주소로 바로 분기하는 것이 아니라 콜스택에 분기할 주소를 쌓고 ret로 리턴하면서 해당 주소로 이동하게 하는 방법이다. 간접분기가 아니므로 BTB를 사용하지 않고 추측실행 시에는 무한루프에 빠지는 구조로 돼 있기 때문에 결과적으로는 모든 추측실행이 실패하며 약간의 성능하락을 감수하면서 해당 취약점에 안전한 구조를 만들 수 있다. 구글이 제시한 예제 코드 하나를 따라가면서 확인해보자. 원래의 간접분기 코드는 다음과 같은 명령이다.
jmp *%r11
이 명령은 레지스터 r11이 가리키는 주소로 분기하라는 전형적인 간접분기 코드이다. 앞서 설명한 대로 이 분기점의 주소는 BTB에 저장됐다가 그 호출내역에 따라 추측실행 시 분기할 주소를 추정하는 데 사용된다. 따라서 BTB를 오염시키는 Spectre Variant 2의 취약점에 의해 공격받을 수 있다. 그런데 이 코드를 다음과 같이 변경해보자.
call set_up_target; (1)
capture_spec: (4)
pause;
jmp capture_spec;
set_up_target:
mov %r11, (%rsp); (2)
ret; (3)
(1)에서 먼저 set_up_target을 함수호출한 후 (2)에서는 간접분기해야 하는 주소인 r11를 rsp의 위치에 저장한다. 그런데 rsp는 함수가 돌아갈 위치를 저장하는 스택포인터이므로 (3)에서 ret을 실행할 때 돌아가는 주소는 원래의 호출 위치 바로 다음인 (4)가 아니라 r11이 된다. 즉 원래 코드의 의도대로 r11의 위치로 이동하는 코드가 완성되는 것이다. 만약 이 코드를 추측실행하려고 해도 CPU는 스택포인터를 덮어 쓴다는 이례적인 상황에 대해서는 알지 못하므로 (1) (2) (3) (4)를 차례로 파이프라인에 적재한 후 마지막으로 jmp capture_spec을 실행하는 무한루프로만 인식한다. 따라서 BTB를 오염시킴으로써 gadget으로 간접분기목표를 지정하려는 공격자의 의도는 실패하게 된다. 이는 CPU 레벨의 조치 없이 Spectre Variant 2를 효과적으로 방어할 수 있는 대책이며, 예상되는 성능상의 불이익도 크지 않다. 다만 retpoline으로 이 취약점에 대응한다면 Spectre Variant 1과 마찬가지로 개별 OS나 어플리케이션 단위로 대응하지 않으면 안 된다.
이미 리눅스 진영에서는 retpoline을 적용한 커널이 릴리즈됐으며, gcc에도 -mindirect-branch={thunk|thunk_inline} 옵션을 줘서 유사한 간접분기코드를 jmp & call 형태로 컴파일해주는 기능이 추가됐다. 리눅스의 경우 사용하는 애플리케이션이 오픈소스인 경우가 많으므로 이때는 커널을 패치하고 사용하는 어플리케이션을 모두 retpoline 스타일으로 리빌드하면 이 취약점으로부터 안전하게 운영할 수 있다.
이 취약점에 대응하는 다른 방법은, CPU 레벨의 마이크로코드 업데이트를 통해 간접분기예측 공격을 못하도록 원천적으로 차단하는 것이다. MS가 이런 방식의 업데이트를 제공하고 있는데, 실질적으로 윈도우에서 모든 애플리케이션을 다시 빌드하는 일은 불가능하기 때문에 불가피한 선택이었을 것이다. 물론 리눅스에서도 같은 방식을 사용할 수 있다. 실제 패치의 내용은 CPU의 마이크로코드 업데이트 후 IBRS, STIBP, IBPB 기능을 활성화하는 것이다. 따라서 OS 레벨에서 하는 일은 별로 없고 공격방어는 전적으로 CPU의 새 기능에 의존한다. 각 기능의 내용은 다음과 같다.
IBRS(Indirect Branch Restricted Speculation) : 간접분기예측 기능 자체를 완전히 꺼버리는 것이다. 커널모드, 또는 커널 및 사용자 모드 양쪽 모두에서 선택적으로 끌 수 있다.
STIBP(Single Thread Indirect Branch Predictors) : 단일 코어 내 하이퍼쓰레딩으로 콘트롤되는 간접분기예측을 막는다.
IBPB(Indirect Branch Prediction Barriers) : 사용자 모드 간, 또는 커널 모드로 컨텍스트 스위칭을 할 때 BTB를 비워서 공격의 가능성을 제거한다.
이런 종류의 업데이트는 CPU의 내부 작동 기작을 바꾸는 매우 큰 변경이라 충분한 테스트를 거쳐서 사용자에게 전달되어야 하나 이번에는 사안이 사안인 만큼 매우 급박하게 만들어서 배포될 수밖에 없었으며 그 때문인지 최근까지 적용 후 블루스크린이나 재부팅이 생긴다는 보고가 속출하고 있다. 또, 각 CPU 세대마다 내부 아키텍처가 모두 다르기 때문에 각각 다른 솔루션을 제공할 수밖에 없는데, 사용자 입장을 생각하면 현재 시장에서 사용되는 모든 CPU에 대한 패치를 작성해야 하나 그러기에는 너무 부담이 크기 때문에 제조사들의 고민이 깊어지고 있다.
인텔의 첫 번째 패치는 브로드웰, 하스웰, 스카이레이크, 카비레이크, 커피레이크에 대응하는 것이었으나 안정성 문제가 대두되자 인텔은 이례적으로 자신들의 패치를 적용하지 말라는 공지를 낸 후 두 번째 패치를 내놓았으며 이 업데이트는 현재의 주력제품인 스카이레이크와 카비레이크, 커피레이크까지만 대응한다. 브로드웰, 하스웰은 아직까지 소식이 없고, 그보다 예전 프로세서인 샌디브릿지, 아이비브릿지에 대한 코드는 여전히 베타 테스트중이라는 것이 인텔의 입장이다. 샌디브릿지가 코어 아키텍처의 두 번째 세대 제품(2011년)이라는 것을 생각하면 그전의 네할렘(2008년)까지 지원하기는 어려워 보이고 인텔의 업데이트는 이 수준에서 마무리 될 가능성이 높다. 또 패치 자체가 안정되어 있지 않아서 성능에 대한 검증은 아직 시작도 못한 상태이므로 특별한 사정이 있지 않다면 이 취약점에 대한 대응은 어느 정도 대기하는 편이 권장된다(성능상 불이익은 한정적일 것으로 추정한다). MeltDown처럼 매우 크리티컬하고 시급하게 대응해야 하는 정도의 위험성이 있는 것은 아니므로 블루스크린이나 커널패닉의 리스크를 감수하면서까지 빨리 패치해야 하는 건 아닌 것이다.
현재 인텔뿐만 아니라 AMD, ARM 개별 CPU에 대한 패치들도 거의 나와 있지만 이 패치는 BIOS를 포함한 하드웨어 벤더의 도구를 통해서만 설치할 수 있기 때문에 대응이 늦어지고 있다. 즉 인텔이 특정 CPU에 대한 마이크로코드 업데이트를 내놓았다고 하더라도 보드나 서버벤더가 BIOS 패치 패키지를 제공하지 않으면 업데이트가 되지 않는 것이다. 따라서 오래된 메인보드를 쓰는 사용자들의 경우는 사실상 패치를 적용할 방법이 없다.
하지만 Spectre Variant 1과 마찬가지로 이 취약점도 성립하기 위한 여러 가지 전제조건들이 있어서 실제 공격은 매우 까다로운 편이다. 공격대상에서 적절한 gadget을 찾아야 하고, 공격자와 공격대상이 모두 접근 가능한 주소공간이 있어야 하며, 같은 BTB를 사용해야 하므로 코어가 다르면 공격의 효과가 없어서 구글의 PoC에서처럼 공격자와 공격대상이 동일한 코어를 사용하도록 pin해야 한다. 공격하고자 하는 간접분기코드의 주소를 먼저 알아야 하고 그로부터 이와 하위주소가 동일한 공격코드를 만들지 않으면 안 된다.
일례로 VM에서 hypervisor를 공격하려고 한다면 일단 어떤 hypervisor를 쓰는지 알아야 하며, 해당 hypervisor의 버전, 메모리 레이아웃, 사용 가능한 gadget의 위치, 간접분기가 일어나는 시점, hypervisor 입장에서 읽기나 쓰기를 할 VM의 메모리 주소 등을 모두 알고 있어야 하고, hypervisor kernel이 실행되는 코어와 공격자의 코어가 동일해야 하며, 간접분기 시 gadget에서 사용하는 레지스터값이 변경되면 안 된다. 아무런 사전 작업 없이 이런 조건들을 모두 맞추는 건 사실상 불가능에 가까우며 그렇기 때문에 실제 Spectre Variant 2가 유효하게 작동하기 위해서는 다른 방법의 침해를 통해 공격하고자 하는 시스템에 대한 정보를 먼저 미리 확보하는 작업이 필수적일 것이다.
이런 까다로운 조건이 있기 때문에 사실 Spectre Variant 1과 마찬가지로 유효한 공격설계를 하는 데는 상당한 노력이 들어가게 되며 뒤집어 얘기하자면 방어하는 측에서 이런 전제조건들 중 최소 하나 이상만 잘 막으면 공격하기가 매우 어려워진다는 뜻도 된다. 따라서 Spectre Variant 1과 마찬가지로 attack surface가 어디에 있는지를 잘 살펴보고 관리해야 하며 출처가 불분명한 모듈을 설치해서는 안 된다. CPU를 pin하는 설정이 있다면 잠재적으로 BTB를 오염시킬 가능성이 있으니 비활성화할지에 대해서도 판단해봐야 한다. BIOS 패치가 있으면 좋겠지만 하드웨어 벤더에서 제공하지 않는다면 해당 시스템은 각별히 보안에 신경 써야 하고 가능하다면 외부 네트워크로부터 분리하여 내부망에만 두는 안도 고려해야 한다.
‘CPU취약점 종합보고서’ 연재를 마치며
▲노규남 가비아 클라우드사업부장/CTO
이렇게 해서 원래 계획한 세 가지 취약점에 대한 설명이 끝났다. 연초부터 불거진 이 사고 때문에 많은 사람들이 불안해하고 있고 아직도 사태는 현재 진행형이지만 필자는 그래도 상황을 그렇게까지 비관적으로 보지는 않는다.
MeltDown은 심각한 취약점이기는 하나 방어책이 없지는 않고 일정 부분 성능을 희생해서 막을 수 있는 것이므로 대응만 빨리 한다면 아주 큰 문제가 되지는 않을 수도 있다. 또 로컬 취약점이라 먼저 공격시스템의 권한을 얻지 않으면 공격이 불가능하므로 지금까지 보안을 잘 관리해온 조직이라면 MeltDown 때문에 갑자기 보안이 취약해진다든가 하는 일은 생기지 않을 것이다. Spectre도 마찬가지로 제대로 공격했을 경우 데이터 유출은 심각해지지만 공격의 성립 조건이 그만큼 까다롭기 때문에 추가적인 보안강화조치 몇 가지만으로도 공격 가능성을 크게 줄일 수 있다.
그리고 지금은 하드웨어적인 취약점을 소프트웨어로 막는 형국이라 근본적으로는 CPU업계에서 이런 문제를 해소한 새로운 제품을 내놓아야 이 상황이 마무리 될 텐데 지난 20여 년간 발전시켜왔던 기본 아키텍처 구조에서 발생한 취약점이라 완전한 해결이 쉽지는 않을 것 같다. 당분간은 학계와 산업계가 머리를 맞대고 새로운 해결책과 이론의 연구에 매진해야 할 것으로 보인다. 어쨌거나 이 취약점들은 당분간 유령(specter)처럼 우리 주위를 떠나지 않고 같이 살게 될 운명이겠지만 늘 그래왔듯이 어려운 상황에서도 답을 찾고 발전해 나가는 것은 인간의 속성이므로 포기하지 않는다면 문제는 결국 해결될 것으로 본다.
[글_ 노규남 가비아 클라우드사업부장 겸 최고기술책임자(ngn@gabia.com)]
■ CPU 취약점 종합보고서 연재순서
① 취약점의 기본원리
② MeltDown과 Spectre Variant 1
③ Spectre Variant 2[끝]
필자 소개_ 노규남은 가비아 클라우드사업부장 겸 최고기술책임자(CTO)로서, IT 업계에서 수십 년간 쌓은 경험을 바탕으로 가비아의 인프라를 고도화하고 발전시키는 역할을 맡고 있다. 최근에는 내부에 쌓이는 서비스 관련 데이터를 신경망으로 처리해 운영을 자동화하고 보안과 클라우드 인프라를 고도화하는 것에 관심을 갖고 있다. 가치투자사이트 밸류스타 기술이사, 영상보안서비스 에버뷰 대표이사를 역임했다.
[오다인 기자(boan2@boannews.com)] <저작권자: 보안뉴스(www.boannews.com) 무단전재-재배포금지>※ 본 기사는 가비아 노규남 CTO가 보안뉴스에 특별기고한 내용을 정리한 것입니다.