Windows PowerShell셸 보안

Don Jones

Windows PowerShell 팀이 새 셸 개발을 위해 모이고 여기저기서 "스크립팅"이라는 단어가 나왔을 때 당황의 신음소리가 꽤 크게 들렸을 것입니다. 결국 관리 스크립팅에 대한 Microsoft의 기존 노력(여기서는 VBScript를 말하는 것임)에 문제가 있었다고 할 수 있습니다.

과도하게 권한 지정된 실행 모델은 대부분의 사용자가 관리자로 로그온한다는 경향과 결합되어 재난이 발생할 기반을 형성했습니다.

Windows PowerShell™ 회의 첫 모임 참가자들은 이런 문제가 반복되지 않도록 해달라고 기도했어야 했을지도 모릅니다. 하지만 참가자들은 그렇게 하지 않았습니다. 결과적으로 보안에 대한 Microsoft의 평가는 크게 향상되었으며, 그 이유는 제품 개발 주기의 후반부가 아니라 첫 단계에서 보안에 대해 생각하기 시작했기 때문입니다. 이러한 철학은 Windows PowerShell에서 매우 확실하게 드러납니다.

내 스크립트가 왜 실행되지 않죠?

새로 설치한 컴퓨터에 Windows PowerShell을 설치하고 .ps1 파일을 두 번 클릭해 보십시오. 그러면 Windows PowerShell이 아니라 메모장이 열립니다. .ps1 파일 이름 확장자(Windows PowerShell 스크립트에 사용되는 확장자)가 셸과 연결되어 있지 않기 때문에 발생하는 현상입니다. 다른 말로 하면 스크립트를 두 번 클릭하여 실행할 수 없다는 의미입니다. 스크립트를 실행하는 유일한 방법은 Windows PowerShell을 열고 스크립트 이름을 입력한 다음 Enter 키를 누르는 것입니다.

실제로는 스크립트 이름을 입력하는 것만으로는 충분하지 않습니다. 그림 1에서 파일 Demo1.ps1이 현재 폴더에 존재하지만 demo1을 입력하고 Enter 키를 누르면 "The term 'demo1' is not recognized as a cmdlet, function, operable program, or script file."(용어 'demo1'이 cmdlet, 함수, 작동 가능한 프로그램 또는 스크립트 파일로 인식되지 않습니다.)이라는 오류가 나타납니다. 파일이 해당 위치에 있는데 왜 이런 오류가 나타날까요?

그림 1 명령 하이재킹을 피하기 위해 Windows PowerShell에서는 스크립트에 대한 경로가 필요함

그림 1** 명령 하이재킹을 피하기 위해 Windows PowerShell에서는 스크립트에 대한 경로가 필요함 **(더 크게 보려면 이미지를 클릭하십시오.)

이것은 Windows PowerShell 보안 모델의 다른 측면입니다. 악의적 사용자가 다른 셸에서 시도하는 해킹 방법 중 하나는 기본 제공 명령과 파일 이름이 같은 스크립트를 만드는 것입니다. 예를 들어 사용자가 스크립트를 실행하도록 하려면 이름이 Dir.ps1인 스크립트를 만들어 폴더에 넣을 수 있습니다. 사용자가 Dir을 입력하고 Enter를 누르면 사용자가 기대한 Dir 명령이 아니라 이 스크립트가 실행될 수 있습니다. 이 방법을 명령 하이재킹이라고 합니다. 하지만 Windows PowerShell에서는 항상 이러한 스크립트에 대한 경로를 제공해야 하기 때문에 Windows PowerShell은 명령 하이재킹으로부터 적절하게 보호됩니다.

demo1을 실행하면 경로가 없기 때문에 작동하지 않지만 ./demo1을 실행하면 작동합니다. 경로(여기서는 현재 폴더)를 지정했기 때문입니다. 기본 제공 명령을 참조할 때는 경로를 입력하지 않기 때문에 이런 명령줄은 기본 제공 명령과 혼동될 가능성이 적습니다. 따라서 경로를 입력하도록 함으로써 명령 하이재킹을 방지하고 Enter 키를 눌렀을 때의 동작에 대한 혼동을 피할 수 있습니다.

스크립트 실행에 대한 정책

Windows PowerShell을 새로 설치하고 올바른 구문을 사용하여 스크립트 실행을 시도한다고 가정합니다. 하지만 이 경우에도 스크립트 실행이 허용되지 않음을 알리는 다른 오류 메시지가 나타납니다. 왜 그럴까요? 이것은 셸의 실행 정책 때문입니다.

셸에서 Get-ExecutionPolicy을 실행하여 현재 실행 정책이 무엇인지 확인할 수 있습니다. 기본적으로 실행 정책은 스크립트를 실행하지 않는 Restricted로 설정되어 있으므로 누구도 스크립트를 실행할 수 없습니다. Windows PowerShell은 기본적으로 스크립트를 실행하는 것이 아니라 대화식으로 사용하는 프로그램입니다. Set-ExecutionPolicy cmdlet를 사용하면 네 가지 가능한 실행 정책 설정 중 하나를 선택할 수 있습니다.

  • 기본 설정인 Restricted는 모든 스크립트의 실행을 허용하지 않습니다.
  • AllSigned는 신뢰할 수 있는 스크립트만 실행합니다.
  • RemoteSigned는 신뢰 여부에 관계없이 로컬 스크립트를 실행합니다. 하지만 인터넷에서 다운로드한 스크립트는 신뢰하는 경우에만 실행할 수 있습니다.
  • Unrestricted는 신뢰하지 않은 스크립트를 포함한 모든 스크립트의 실행을 허용합니다.

현실적으로는 AllSigned가 가장 낮은 설정이며 프로덕션 컴퓨터는 이것으로 설정해야 합니다. 필자의 경우 개발 및 테스트 환경에서는 RemoteSigned가 유용하다고 생각하지만 일반 사용자의 경우에는 그렇지 않을 수 있습니다. 또한 Unrestricted는 전혀 필요 없으며 향후 버전의 Windows PowerShell에서 이 과도하게 권한 지정된 설정을 제거해도 괜찮을 것입니다.

신뢰 문제

사용자의 컴퓨터는 특정 루트 인증 기관(CA), 즉 디지털 인증서를 발행하는 서버를 신뢰하도록 사전 구성되어 있습니다. 그림 2에서는 신뢰할 수 있는 루트 CA를 나열하는 인터넷 옵션 제어판 응용 프로그램을 보여 줍니다. Windows Vista®에서 이 목록은 꽤 짧으며 몇 개의 주요 상용 루트 CA만 포함합니다. 이와 반대로 Windows® XP의 기본 목록은 크며 들어본 적 없는 많은 루트 CA도 포함합니다. 루트 CA가 이 목록에 있다는 것은 루트 CA를 운영하는 회사가 누군가에게 디지털 인증서를 발행하기 전에 그 사람의 신원을 제대로 확인하는 것으로 신뢰한다는 의미와 같습니다.

Class III 디지털 인증서(보통 코드 서명 인증서라고 함)를 얻을 때 CA(상용 CA이거나 조직 내의 사설 CA일 수 있음)가 여러분의 신원을 검증해야 합니다. 이 디지털 인증서는 전자 여권 또는 신분증과 같습니다. 예를 들어 '저는 Don Jones입니다'라는 의미의 ID를 제공하기 전에 CA가 몇 단계를 거쳐 그 사람이 실제로 Don Jones인지 확인해야 합니다. 인증서를 사용하여 Windows PowerShell 스크립트에 디지털 서명하는 것은(Set-AuthenticodeSignature cmdlet를 사용하여) 스크립트에 이름을 서명하는 것입니다. 물론 다른 사람의 이름이 포함된 거짓 인증서를 얻을 수 있다면 스크립트에 그 사람의 이름을 서명할 수 있습니다. 바로 이런 이유 때문에 그림 2의 목록에 신뢰할 수 있는 CA만 표시되는 것이 중요합니다.

그림 2 Windows Vista에서 기본적으로 신뢰할 수 있는 루트 CA

그림 2** Windows Vista에서 기본적으로 신뢰할 수 있는 루트 CA **(더 크게 보려면 이미지를 클릭하십시오.)

Windows PowerShell은 스크립트를 신뢰할 수 있는지 검사할 때(AllSigned 및 RemoteSigned 실행 정책 설정에서 수행됨) 다음 세 가지를 질문합니다.

  • 스크립트에 서명이 되어 있습니까? 서명이 되어 있지 않으면 스크립트를 신뢰하지 않습니다.
  • 서명이 변조되지 않았습니까? 다른 말로, 스크립트가 서명된 이후 변경되었습니까? 서명이 변조된 경우 스크립트를 신뢰하지 않습니다.
  • 신뢰할 수 있는 루트 CA가 발행한 디지털 인증서를 사용하여 서명이 생성되었습니까? 그렇지 않은 경우에는 스크립트를 신뢰하지 않습니다.

이 달의 CMDLET: Set-AuthenticodeSignature

Set-AuthenticodeSignature는 Windows PowerShell 스크립트에 디지털 서명하기 위한 키이며, 이를 통해 셸의 가장 안전한 실행 정책인 AllSigned를 사용할 수 있습니다. 이 cmdlet를 사용하려면 설치된 코드 서명 인증서를 인출하는 다른 Get-ChildItem으로 시작할 수 있습니다.

$cert = Get-ChildItem –Path cert:\CurrentUser\my –codeSigningCert

이 파일 경로를 설치된 인증서 경로로 바꿔야 합니다. 설치된 모든 인증서에는 cert: drive를 사용하여 액세스할 수 있습니다. 인증서가 로드된 후 다음을 실행하여 스크립트에 서명합니다.

Set-AuthenticodeSignature MyScript.ps1

–cert $cert

물론 실제 .ps1 스크립트 파일의 전체 경로를 지정해야 합니다. 그러면 셸은 파일에 서명 블록을 추가합니다.

그러면 신뢰는 어떻게 보안을 향상시킬까요? 물론 해커가 악성 스크립트를 작성하고, 이를 서명한 다음 다른 사용자가 이를 실행하도록 유도할 가능성도 있습니다. 이 경우 스크립트는 서명이 되어 있으므로 실행됩니다. 하지만 서명이 되었기 때문에 이 서명을 사용하여 작성자의 신분을 찾아서 법률 기관 신고 등과 같은 적절한 조치를 취할 수 있습니다. 하지만 악성 스크립트를 만들어서 자신의 실제 이름으로 서명하는 해커는 없을 것입니다.

물론 악성 사용자가 신원 확인 프로세스가 제대로 갖춰지지 않은 CA 등으로부터 다른 사람의 신원이 적용된 인증서를 얻을 수 있다면 서명을 사용하여 실제 용의자를 찾아낼 수 없을 것입니다. 바로 이런 이유 때문에 신뢰하는 루트 CA에서 만족스러운 신원 확인 프로세스를 사용하는지 확인해야 합니다.

AllSigned 실행 정책 설정을 사용하는 경우, 작성한 모든 스크립트를 실행하기 전에 해당 스크립트에 디지털 서명을 해야 합니다. Set-AuthenticodeSignature cmdlet는 사용법이 꽤 쉽지만 다소 번거로운 것도 사실입니다. 경우에 따라 타사 소프트웨어가 편리할 수 있습니다. 개인적으로, 작성한 스크립트를 지정한 인증서로 자동 서명하는 스크립트 편집기나 가상 개발 환경을 사용하는 것을 추천합니다. 이 방법을 사용하면 서명 사용이 투명하며 추가적인 작업이 필요 없습니다. 이를 지원하는 편집기 및 개발 환경에 대한 정보가 필요한 경우 온라인 스크립팅 포럼(예를 들어 SscriptingAnswers.com의 필자 사이트)을 방문하여 다른 Windows PowerShell 사용자들은 어떤 방법을 사용하는지 묻는 질문을 게시해 보십시오.

인증서를 얻은 뒤에는 다음을 실행하여 특정 위치의 모든 스크립트에 서명할 수 있습니다.

Get-Childitem *.ps1 | %{Set-AuthenticodeSignature $_.fullname $cert}

중앙 집중식 보안

Windows PowerShell 실행 정책은 컴퓨터 단위로 구성할 수 있습니다. 하지만 엔터프라이즈 환경에서는 이 방식이 적합한 솔루션이 아니므로 이 경우 정책 그룹을 사용할 수 있습니다. Windows PowerShell 관리 템플릿은 go.microsoft.com/fwlink/?LinkId=93675에서 다운로드할 수 있습니다. 전체 도메인에 영향을 주는 그룹 정책 개체(GPO)에 파일을 지정하고 Restricted로 지정합니다. 이렇게 하면 Windows PowerShell이 설치된 위치에 관계 없이 스크립트가 실행되지 않습니다. 그러면 자신의 워크스테이션처럼 스크립트를 실행해야 하는 컴퓨터에서만 추가적인 권한 설정(예: AllSigned)을 적용할 수 있습니다.

대체 자격 증명

기존의 Windows용 관리 스크립팅 언어와 달리 Windows PowerShell은 보안상 안전한 방식으로 대체 자격 증명을 다룰 준비도 되어 있습니다. 예를 들어 Get-WMIObject cmdlet에는 원격 WMI 연결에 대한 대체 자격 증명을 지정할 수 있는 -credential 매개 변수가 있습니다. 매개 변수는 사용자 이름을 받지만 암호는 받지 않음으로써 민감한 암호를 일반 텍스트 스크립트에 하드 코드하는 것을 방지합니다. 대신 사용자가 사용자 이름을 입력하면 Windows PowerShell은 대화 상자를 사용하여 암호를 묻는 메시지를 표시합니다. 대체 자격 증명을 다시 사용하려면 Get-Credential cmdlet를 사용하여 자동화 정보를 저장할 수 있습니다.

$cred = Get-Credential DOMAIN\USER

즉시 암호를 묻는 메시지가 나타나고 최종 자격 증명이 변수 $cred에 저장됩니다. 그러면 $cred 변수는 필요할 때마다 -credential 매개 변수로 전달될 수 있습니다. ConvertTo-SecureString 및 ConvertFrom-SecureString cmdlet를 사용하여 자격 증명을 암호화된 문자열로 변환하거나 이전에 암호화된 문자열을 다시 자격 증명으로 변환할 수도 있습니다.

여기서 문제는 암호화 키가 보안에 취약한 일반 텍스트 스크립트에 저장된다는 점입니다. 따라서 이 방법 대신 Get-Credential 호출을 Windows PowerShell 프로필에 추가할 수 있습니다. 이렇게 하면 Windows PowerShell을 실행했을 때 곧바로 사용자 이름과 암호를 묻는 메시지가 나타나며 이 두 정보는 $cred라는 변수에 저장됩니다. 이 방법을 통해 도메인 관리자 계정을 나타내는 셸에서 언제라도 $cred 변수를 사용할 수 있습니다. 또한 해당 자격 증명을 저장할 필요가 없습니다. 자격 증명은 셸을 열 때마다 다시 생성되므로 저장할 필요가 없습니다.

기본 보안

기본적으로 스크립팅을 지원하는 관리 셸에서 사용할 수 있는 가장 안전한 보안 설정으로 Windows PowerShell을 설치 및 구성할 수 있습니다. 이러한 설정을 변경한 경우 이외에는 Windows PowerShell은 가능한 최선의 보안을 유지합니다. 다른 말로 하면 Windows PowerShell에서 보안이 취약해지는 것은 사용자의 결정이나 작업이 원인입니다. 따라서 기본값을 변경하려면 파일 확장자를 다시 구성하고, 실행 정책을 변경하는 등의 작업을 해야 합니다. 작업의 결과를 확실히 알고 있으며 자신의 변경에 책임질 준비가 되었을 때만 기본값을 변경하십시오.

Don Jones는 SAPIEN Technologies의 수석 스크립팅 전문가이자 ScriptingTraining.com의 강사입니다. 문의 사항이 있으면 ScriptingAnswers.com을 통해 연락하십시오.

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