Windows PowerShell여기 서명해 주세요

Don Jones

지난 2008년 1월 Windows PowerShell 칼럼에서 Windows PowerShell 스크립트에 있어서 디지털 서명이 얼마나 중요한지에 대해서는 이미 강조한 바 있습니다. 그리고 AllSigned 외에 다른 실행 정책을 사용할 경우 사용자 환경에 중대한 보안 취약점이 발생할 수 있는 몇 가지 시나리오에 대해서도 설명했습니다.

자세히 설명하지 않은 내용을 들라면 실제로 스크립트에 서명하는 방법이 있습니다. 이 내용은 technetmagazine.com/issues/2008/01/PowerShell을 참조하면 됩니다. 그렇다면 이번 달에는 어떤 내용을 다룰까요?

서명 이상의 그 무엇

서명이라는 단어는 여기서 다루려는 내용에 알맞은 기술 용어이지만 그 자체로는 실제 기능을 제대로 나타내지 못합니다. 스크립트에 서명한다고 해서 계약서 또는 신용 카드 전표의 경우처럼 스크립트를 승인하거나 인증하는 것은 아니기 때문입니다. 디지털 보안에서 서명은 어떤 항목에 자신의 ID를 첨부하여 해당 항목이 수정되지 않은 원본 그대로의 상태 또는 조건임을 보증하는 프로세스를 말합니다. 그리고 이러한 프로세스는 암호화를 기반으로 하며, 적어도 이 시나리오의 경우 암호화는 한 쌍의 암호화 키로 시작됩니다.

이러한 한 쌍의 키는 서로 다르기 때문에 비대칭 키라고도 합니다. 즉, 서명한 사용자만 액세스할 수 있는 개인 키와 누구나 액세스할 수 있는 공개 키의 쌍으로 이루어집니다. 간단하게 설명하자면 개인 키를 사용해 암호화한 모든 항목은 기본적으로 일치하는 공개 키로만 암호를 해독할 수 있습니다.

이러한 암호화가 어떻게 작동하는지 알아보겠습니다. 이번에도 칼럼을 진행하는 데 필요한 내용만 최대한 간단히 설명하겠습니다. 필자는 인증서에 들어 있는 개인 키를 사용하여 Windows PowerShell® 스크립트에 서명하려 합니다. Windows PowerShell 자체에는 스크립트와 인증서를 가져와서 실제 서명을 수행하는 cmdlet이 있습니다. 이 cmdlet에 대해서는 잠시 후에 설명하겠습니다. Windows PowerShell에서는 이러한 프로세스를 수행할 때 스크립트를 가져와서 필자의 개인 키를 통해 암호화합니다. 이렇게 암호화된 복사본은 스크립트 아래쪽에 알아볼 수 없는 텍스트 형식의 일련의 주석으로 추가됩니다(그림 1 참조). 필자의 ID도 이러한 주석으로 인코딩되지만 암호화되지는 않습니다. 따라서 ID 자체는 암호화 기술 없이도 읽을 수 있습니다.

그림 1 스크립트 맨 아래에 저장된 서명 블록

그림 1** 스크립트 맨 아래에 저장된 서명 블록 **(더 크게 보려면 이미지를 클릭하십시오.)

그리고 나중에 Windows PowerShell은 서명을 찾아 필자의 ID를 디코딩하여 공개 키를 얻는 데 사용합니다. 서명의 나머지 부분은 필자의 공개 키로만 해독할 수 있으므로 Windows PowerShell에서 서명을 해독할 수 있다면 필자가 스크립트에 서명했다는 사실이 자연스럽게 증명됩니다. 다른 사람이 서명했다면 필자의 공개 키로는 서명을 해독할 수 없기 때문입니다. 서명이 해독되면 Windows PowerShell은 서명으로 암호화된 복사본과 스크립트를 비교합니다. 두 스크립트가 일치하면 서명이 변조되지 않은 것으로 간주됩니다. 그런데 두 스크립트가 서로 다르면 서명이 손상되어 잘못된 것으로 간주됩니다.

서명은 이러한 방식으로 다른 사람의 눈에 띄지 않게 일반 텍스트 스크립트가 수정되지 않도록 보호합니다. 스크립트 자체는 쉽게 수정할 수 있지만 서명은 필자의 개인 키 없이는 수정된 스크립트에 맞게 변경할 수 없습니다. 그리고 이러한 개인 키는 필자만 소유합니다.

여기서는 기본적인 기술 프로세스만 아주 간략하게 설명했습니다. 실제로는 서명에 공개 키의 복사본, 키를 발급한 CA(인증 기관)에 대한 정보 등 훨씬 많은 정보가 포함될 수 있습니다. 그러나 여기서 설명하는 내용만으로도 이 프로세스의 핵심적인 부분을 개괄하고 서명이 실질적으로 스크립트의 무단 수정을 방지하는 데 효과가 있음을 강조하는 데에는 충분하리라 생각합니다.

개인 키가 다른 사람의 손에 들어가면 이러한 프로세스는 의미가 없기 때문에 개인 키의 보호야말로 중요한 보안 요소라 할 수 있습니다. Windows에 키를 설치할 때에는 즉시 암호로 보호하여 악의적인 프로세스에 키가 무단으로 사용되는 일이 없도록 해야 합니다. 이 경우 개인 키를 스마트 카드에 보관하면 보다 효과적으로 보호할 수 있습니다. 스마트 카드의 개인 키는 절대 외부로 유출되지 않기 때문입니다. 대신 암호화할 데이터가 판독기 하드웨어를 통해 카드로 전송되고, 카드 자체의 회로에서 암호화를 수행한 후 결과를 다시 전송합니다.

인증서 얻기

이달의 Cmdlet: Export-CSV

PowerShellCommunity.org 포럼 참가자들은 Windows PowerShell에서 Microsoft Excel®로 데이터를 내보낼 수 있는지 많이 묻곤 합니다. 당연히 가능합니다. Excel은 기본적으로 CSV 파일을 열고 편집하고 저장할 수 있으므로 Export-CSV cmdlet을 사용하면 됩니다. 예를 들어 서비스 목록을 내보내려면 Get-Service | Export-CSV MyServices.csv를 실행하면 됩니다. 사실 Export-CSV는 모든 파이프라인의 끝에 첨부할 수 있으며 해당 파이프라인의 모든 개체가 지정한 CSV 파일로 내보내집니다. 기본적으로 Export-CSV는 파일의 맨 위에 헤더 줄을 추가합니다. 이 헤더는 내보낸 개체의 형식을 지정하는 데 사용됩니다. 그리고 이 줄은 주석으로 처리되므로 Excel에서 파일을 여는 데 방해가 되지 않습니다. 형식 정보를 내보내지 않으려면 Export-CSV에 -notype 매개 변수를 추가하면 됩니다. 또한 -force 매개 변수를 추가하여 기본적으로 표시되는 확인 메시지를 표시하지 않고 같은 이름의 기존 CSV 파일을 덮어쓰거나, 이름에서 잘 알 수 있듯이 -noClobber라는 매개 변수를 추가하여 기존 파일을 덮어쓰지 않도록 할 수 있습니다.

스크립트에 서명하려면 Class III Authenticode 코드 서명 인증서라는 특별한 인증서가 필요합니다. 이 인증서는 주로 세 가지 방법으로 얻을 수 있습니다. 첫째로, 조직의 내부 PKI(공개 키 인프라)가 있으면 해당 PKI를 사용합니다. 잘 구현된 PKI의 경우 루트 CA가 조직의 모든 컴퓨터에서 신뢰됩니다. 이는 CA에서 발급한 인증서를 조직 내에서 사용하기 위한 필수 조건입니다.

Windows® 2000부터 Windows Server®에는 자체 인증서 서버 소프트웨어가 포함되어 있는데, 이 소프트웨어를 사용하면 직접 PKI를 만들 수 있습니다. PKI를 완벽하게 구현하려면 치밀하게 계획해야 하지만 단지 코드 서명 인증서 발급 때문에 PKI가 필요한 경우에는 복잡한 계획 작업을 굳이 거치지 않아도 됩니다. 즉, 그룹 정책을 사용하여 CA의 루트 인증서를 컴퓨터에 배포하여 해당 컴퓨터에서 신뢰되도록 하기만 하면 됩니다.

둘째로, 상용 CA를 사용할 수 있습니다. 상용 CA를 사용할 경우 주요 CA 중 하나를 선택하면 해당 CA가 발급한 인증서를 신뢰하도록 조직의 컴퓨터가 이미 구성되어 있을 가능성이 크다는 장점이 있습니다. 한 가지 유의할 것은 Windows XP에서는 기본적으로 신뢰되는 CA 수가 많지만 Windows Vista®에서는 그 수가 훨씬 적다는 것입니다. 많이 사용되는 상용 CA로는 VeriSign(verisign.com)이 있습니다. 그 외에도 CyberTrust(cybertrust.com), Thawte (thawte.com) 등 고려할 만한 상용 CA가 많습니다.

코드 서명 인증서를 얻는 세 번째 방법은 Makecert.exe와 같은 도구를 사용해 자체 서명된 인증서를 만드는 것입니다. Windows Platform SDK와 함께 제공되는 Makecert.exe는 몇 가지 Microsoft® Office 버전에 설치되며 다른 곳에도 많이 사용됩니다. 자체 서명된 인증서의 장점은 무료로 사용할 수 있고 인프라가 필요 없다는 점입니다. 반면 해당 컴퓨터에서만 사용 가능하다는 단점도 있지만, 자신의 컴퓨터에서 스크립트를 실행(코드 서명 테스트 또는 일반적인 실험용으로)하는 데에만 사용하려는 경우에는 Makecert.exe가 바람직한 선택이 될 수 있습니다. 이 도구에 대한 자세한 내용은 go.microsoft.com/fwlink/?LinkId=108538에서 확인할 수 있습니다. 지난 수년 동안 이 도구의 여러 버전이 발표되었기 때문에 현재 사용자의 컴퓨터에서 실행하는 버전이 설명서의 내용과 다르게 작동할 수도 있다는 점을 유의하십시오.

Makecert.exe가 준비되면 Windows PowerShell 명령줄에서 다음과 같은 코드를 실행하여 자체 서명된 인증서를 만들 수 있습니다. 이 칼럼에서는 cmd.exe를 사용하는 경우는 설명하지 않겠습니다.

makecert -n "CN=MyRoot" -a sha1 –eku
1.3.6.1.5.5.7.3.3 -r -sv root.pvk root.cer 
–ss Root -sr localMachine

그리고 다음 코드를 실행합니다.

makecert -pe -n "CN=MyCertificate" -ss MY 
–a sh1 -eku 1.3.6.1.5.5.7.3.3 -iv root.pvk 
–c root.cer

그러면 Makecert.exe가 키를 보호하는 데 사용할 암호를 묻고 인증서를 만듭니다. Windows PowerShell에서 다음 코드를 실행하면 설치 여부를 확인할 수 있습니다.

gci cert:\CurrentUser\My -codesigning

이 코드를 실행하면 CERT: 드라이브(Windows 인증서 저장소)의 모든 항목, 즉 코드 서명 인증서의 목록이 표시됩니다. Windows PowerShell에는 이러한 모든 프로세스에 대한 설명도 포함되어 있습니다. 이러한 설명을 보려면 About_Signing 도움말을 실행하고 화면에 표시되는 내용을 어느 정도 읽어 보십시오.

스크립트 서명

이제 인증서와 스크립트가 준비되었으므로 실제로 스크립트에 서명할 차례입니다. 마땅한 스크립트가 없다면 테스트용으로 간단히 하나를 만들면 됩니다. Windows PowerShell에서 다음 코드를 입력하기만 하면 됩니다.

$cert = @(gci cert:\currentuser\my
-codesigning)[0]
Set-AuthenticodeSignature myscript.ps1 $cert

첫 부분에서는 먼저 설치된 코드 서명 인증서를 검색합니다. 여러 인증서가 설치되어 있는 경우 첫 번째 인증서 외에 다른 인증서를 사용하려면 "0"을 해당 번호로 바꾸면 됩니다. 두 번째 부분에서는 파일에 서명합니다. 물론 이때에는 파일 이름을 서명하려는 파일 이름으로 변경해야 합니다. 매우 간단하지 않습니까? 이 과정에서 약간의 수고가 들어간 부분을 솔직히 밝히자면 Set-AuthenticodeSignature라는 cmdlet 이름이 너무 길어서 Sign이라는 별칭을 만든 것입니다. 이제 다음 코드를 실행하면 됩니다.

Sign myscript.ps1 $cert

해당 스크립트를 열면 맨 아래에 서명 블록이 삽입된 것을 확인할 수 있습니다. 그리고 실행 정책을 AllSigned(Set-ExecutionPolicy AllSigned)로 설정하고 스크립트를 실행해보면 문제 없이 작동하는 것을 확인할 수 있습니다. 이제 스크립트를 수정하고 저장할 수 있는데, 이 경우 다시 서명하지 않도록 주의해야 합니다. 다시 서명하면 서명이 손상되어 Windows PowerShell에서 수정된 버전의 실행이 거부됩니다.

약간의 수고와 큰 효과

이러한 프로세스가 그 효과에 비해 너무 번거롭다고 생각하십니까? 인증서에 500달러를 투자하거나 완전히 새로운 인프라 요소를 구현하지 않고 몇 가지 관리 작업을 스크립팅할 수 있다면 좋겠는데 요구 사항이 너무 많습니까? 필자 자신도 관리자의 입장에서 여러분의 생각은 충분히 이해할 수 있습니다. 그러나 단언컨대 여기서 설명하는 내용은 그만한 가치가 있습니다.

사실 보안과 관련해서는 항상 어느 정도의 노력과 비용이 뒤따릅니다. 바이러스 백신 소프트웨어가 골칫거리일 수도 있지만 그렇다고 바이러스 백신 소프트웨어를 사용하지 않을 수는 없습니다. 방화벽 소프트웨는 확실히 귀찮고 번거롭지만 방화벽 없이 안전을 보장할 수는 없습니다. 그리고 Windows Vista UAC(사용자 계정 컨트롤)도 번거롭게 여겨질 수 있지만 컴퓨터의 보안을 강화하기 위한 약간의 수고일 따름입니다. 어쨌든 우리의 궁극적인 목표가 바로 이렇게 강화된 보안이 아닙니까?

Windows PowerShell은 강력한 도구이지만 다른 도구와 마찬가지로 악의적인 사용자에 의해 보안 취약점으로 악용될 소지를 항상 가지고 있습니다. 따라서 이러한 악의적인 사용자를 막기 위한 조치가 중요합니다.

그러한 맥락에서 코드 서명은 가장 효과적인 방법이며 번거로운 작업이 많이 요구되지도 않습니다. 예를 들어 필자의 경우에는 저장 단추를 누를 때마다 스크립트에 자동으로 서명하는 그래픽 스크립트 편집기를 사용하기 때문에 코드 서명 프로세스에 신경을 쓰지 않아도 됩니다.

그래픽 편집기 없이 훨씬 간편하게 처리할 수 있는 방법도 있습니다. 예를 들어 고유한 Windows PowerShell 프로필(문서 폴더의 WindowsPowerShell 폴더에 Microsoft.PowerShell_profile.ps1이라는 파일을 생성)을 만들고 거기에 다음 함수를 추가하면 됩니다.

function sign ($filename) {
  $cert = @(gci cert:\currentuser\my 
-codesigning)[0]
Set-AuthenticodeSignature $filename $cert
}

그리고 다음을 입력하여 간단히 스크립트에 서명할 수 있습니다.

Sign c:\scripts\myscript.ps1

물론, 이 경우 해당 프로필 스크립트를 가장 먼저 서명해야 합니다. 여기서 핵심은 가능한 한 편리하게 스크립트에 서명할 수 있도록 하자는 것입니다.

코드 서명 인증서를 발급하는 용도로만 사용할 단일 서버 PKI를 배포하는 일을 그리 어렵지 않습니다. 그러나 특히 다른 용도로도 사용하는 경우에는 루트 CA를 보호하고 재해 복구 기능을 제공하는 등 PKI에 대해 철저히 연구하고 계획해야 합니다. 환경에서 스크립트를 실행하는 사용자가 여러분 혼자라면 언제든 Makecert.exe를 사용할 수 있습니다. Makecert.exe로 만든 인증서를 보호하는 방법에 대한 자세한 내용은 About_Signing Windows PowerShell 도움말 항목에서도 제공됩니다.

Don JonesWindows PowerShell: TFM and VBScript, WMI, and ADSI Unleashed의 저자입니다. 문의 사항이 있으면 PowerShellCommunity.org 웹 사이트를 통해 연락하시기 바랍니다.

© 2008 Microsoft Corporation 및 CMP Media, LLC. All rights reserved. 이 문서의 전부 또는 일부를 무단으로 복제하는 행위는 금지됩니다..