Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> ระบบ >> Windows Server

วิธีลงนามสคริปต์ PowerShell (PS1) ด้วยใบรับรอง Code Signing

สคริปต์หรือไฟล์นำออกที่มีลายเซ็นดิจิทัลช่วยให้ผู้ใช้มั่นใจได้ว่าไฟล์เป็นต้นฉบับและโค้ดไม่ได้ถูกเปลี่ยนแปลงโดยบุคคลที่สาม PowerShell เวอร์ชันปัจจุบันมีเครื่องมือสำหรับการลงนามโค้ด (code signing) ไฟล์สคริปต์ *.ps1 โดยใช้ใบรับรองดิจิทัลในตัว

ประเภทใบรับรองสำหรับการลงนาม

สามารถลงนามสคริปต์ PowerShell ได้ด้วยประเภทใบรับรองพิเศษคือ Code Signing ใบรับรองนี้สามารถขอได้จาก:

  • ผู้ออกใบรับรองเชิงพาณิชย์ภายนอก (Commercial CA)
  • CA ภายในองค์กร (Enterprise CA)
  • ใบรับรองเซลฟ์ไซด์ (Self-signed certificate)

ขอใบรับรองจาก Enterprise CA

สมมติว่าบริการ PKI (Active Directory Certificate Services) ถูกปรับใช้ในโดเมนแล้ว สามารถขอใบรับรองใหม่ได้โดยไปที่ https://CA-server-name/certsrv และขอใบรับรองใหม่ด้วยเทมเพลต Code Signing (เทมเพลตนี้ต้องเปิดใช้งานในคอนโซล Certification Authority ก่อน)

ผู้ใช้ยังสามารถขอใบรับรองสำหรับการลงนามสคริปต์ PowerShell จากสแนปอิน MMC Certificates → My Account → Personal → All Tasks → Request a new certificate

หากขอใบรับรองด้วยตนเอง ควรมีไฟล์ใบรับรอง x509 ที่มีนามสกุล .cer ใบรับรองนี้ต้องติดตั้งในที่เก็บใบรับรองท้องถิ่นของคอมพิวเตอร์

สามารถใช้คำสั่ง PowerShell ต่อไปนี้เพื่อเพิ่มใบรับรองไปยัง Trusted Root Certificates ของคอมพิวเตอร์:

$certFile = Export-Certificate -Cert $cert -FilePath C:\ps\certname.cer
Import-Certificate -CertStoreLocation Cert:\LocalMachine\AuthRoot -FilePath $certFile.FullName

สร้างใบรับรอง Self-signed

หากต้องการใช้ใบรับรองเซลฟ์ไซด์ ให้ใช้ cmdlet New-SelfSignedCertificate เพื่อสร้างใบรับรอง CodeSigning ด้วยชื่อ DNS testPC1:

New-SelfSignedCertificate -DnsName testPC1 -Type CodeSigning
$cert = New-SelfSignedCertificate -Subject "Cert for Code Signing" -Type CodeSigningCert -DnsName test1 -CertStoreLocation cert:\LocalMachine\My

หลังสร้างใบรับรองแล้ว ให้ย้ายจาก container Intermediate ไปยัง Trusted Root โดยใช้คอนโซล Certificate Manager (certmgr.msc)

ตั้งค่า Execution Policy สำหรับสคริปต์ที่ลงนามแล้ว

หลังได้ใบรับรองแล้ว สามารถตั้งค่า PowerShell Script Execution Policy ให้อนุญาตให้รันเฉพาะสคริปต์ที่ลงนามแล้ว โดยค่าเริ่มต้นของ PowerShell Execution Policy บน Windows 10/Windows Server 2016 คือ Restricted (บล็อกการรันสคริปต์ PowerShell ทุกตัว)

File C:\ps\script.ps1 cannot be loaded because running scripts is disabled on this system.

เพื่ออนุญาตให้รันเฉพาะสคริปต์ PS1 ที่ลงนามแล้ว ให้เปลี่ยน Execution Policy เป็น AllSigned หรือ RemoteSigned (ต่างกันที่ RemoteSigned ต้องการลายเซ็นเฉพาะสคริปต์ที่ดาวน์โหลดจากอินเทอร์เน็ต):

Set-ExecutionPolicy AllSigned –Force

ในโหมดนี้ เมื่อรันสคริปต์ PowerShell ที่ไม่ได้ลงนาม จะเกิดข้อผิดพลาด:

File C:\script.ps1 cannot be loaded. The file script.ps1 is not digitally signed. You cannot run this script on the current system.

ยังสามารถอนุญาตให้รันสคริปต์ PowerShell ที่ลงนามแล้วได้โดยใช้พารามิเตอร์ Group Policy Turn on Script Execution ภายใต้ Computer Configuration → Policies → Administrative Templates → Windows Components → Windows PowerShell เปลี่ยนค่าเป็น Allow only signed scripts

ลงนามไฟล์สคริปต์ PowerShell

ขั้นแรก ต้องดึงใบรับรอง CodeSign จากที่เก็บใบรับรองท้องถิ่นของผู้ใช้ปัจจุบัน เริ่มด้วยการแสดงรายการใบรับรองทั้งหมดที่สามารถใช้ลงนามโค้ดได้:

Get-ChildItem cert:\CurrentUser\my –CodeSigningCert

ในกรณีนี้ เราจะเอาใบรับรองตัวแรกจากที่เก็บส่วนตัวของผู้ใช้และเก็บไว้ในตัวแปร $cert:

$cert = (Get-ChildItem cert:\CurrentUser\my –CodeSigningCert)[0]

หากย้ายใบรับรองไปที่ Trusted Root Certificate Store ให้ใช้คำสั่ง:

$cert = (Get-ChildItem Cert:\LocalMachine\AuthRoot –CodeSigningCert)[0]

จากนั้นใช้ใบรับรองนี้ลงนามไฟล์ PS1 ด้วยสคริปต์ PowerShell ของคุณ:

Set-AuthenticodeSignature -Certificate $cert -FilePath C:\PS\testscript.ps1

หรือใช้คำสั่งนี้ (ในกรณีนี้เราเลือกใบรับรองเซลฟ์ไซด์ที่สร้างไว้ก่อนหน้านี้โดย DnsName):

Set-AuthenticodeSignature C:\PS\test_script.ps1 @(gci Cert:\LocalMachine\AuthRoot -DnsName testPC1 -codesigning)[0]
เคล็ดลับ. Cmdlet Set-AuthenticodeSignature มีพารามิเตอร์ TimestampServer מיוחד ที่ระบุ URL ของบริการ Timestamp หากเว้นว่างไว้ สคริปต์ PS จะหยุดทำงานหลังจากใบรับรองหมดอายุ ตัวอย่างการตั้งค่า timestamp server: -TimestampServer "https://timestamp.verisign.com/scripts/timstamp.dll"

หากพยายามใช้ใบรับรอง SSL/TLS ทั่วไปในการลงนามสคริปต์ จะเกิดข้อผิดพลาด:

Set-AuthenticodeSignature: Cannot sign code. The specified certificate is not suitable for code signing.

สามารถลงนามไฟล์สคริปต์ PowerShell ทั้งหมดในโฟลเดอร์พร้อมกันได้:

Get-ChildItem c:\ps\*.ps1| Set-AuthenticodeSignature -Certificate $Cert

ตรวจสอบลายเซ็นของสคริปต์

สามารถตรวจสอบว่าไฟล์สคริปต์ PowerShell ถูกลงนามถูกต้องหรือไม่ได้ โดยใช้ cmdlet Get-AuthenticodeSignature หรือเปิดคุณสมบัติไฟล์ PS1 แล้วไปที่แท็บ Digital Signatures

Get-AuthenticodeSignature c:\ps\test_script.ps1 | ft -AutoSize

หากมีคำเตือน UnknownError ขณะรันคำสั่ง Set-AuthenticodeSignature แสดงว่าใบรับรองนั้นไม่ได้รับเชื่อถือ เนื่องจากอยู่ในที่เก็บใบรับรองส่วนตัวของผู้ใช้

ต้องย้ายไปยัง Trusted Root Certificates (อย่าลืมตรวจสอบที่เก็บใบรับรอง Windows สำหรับใบรับรองที่น่าสงสัยและอัปเดตรายการ Trusted Root Certificates เป็นระยะ):

Move-Item -Path $cert.PSPath -Destination "Cert:\LocalMachine\Root"

ตอนนี้เมื่อตรวจสอบลายเซ็นของไฟล์ PS1 ควรคืนค่าสถานะ Valid

บล็อกลายเซ็นในไฟล์สคริปต์

เมื่อลงนามไฟล์สคริปต์ PowerShell Cmdlet Set-AuthenticodeSignature จะเพิ่มบล็อกลายเซ็นดิจิทัลไปที่ท้ายไฟล์ข้อความ PS1:

# SIG # Begin signature block ........... ........... # SIG # End signature block

บล็อกลายเซ็นมีแฮชของสคริปต์ซึ่งถูกเข้ารหัสด้วยคีย์ส่วนตัว

ครั้งแรกที่พยายามรันสคริปต์ จะมีคำเตือนปรากฏ:

Do you want to run software from this untrusted publisher? File C:\PS\script.ps1 is published by CN=testPC1 and is not trusted on your system. Only run scripts from trusted publishers.

หากเลือก [A] Always run ตอนรันสคริปต์ครั้งแรก ครั้งต่อไปที่รันสคริปต์ที่ลงนามด้วยใบรับรองนี้ จะไม่มีคำเตือนปรากฏอีก

เพื่อป้องกันไม่ให้คำเตือนปรากฏ ต้องคัดลอกใบรับรองไปยัง Certificate Authority Trusted Publishers เช่นกัน ใช้การ Copy-Paste ในคอนโซล Certificates เพื่อคัดลอกใบรับรองไปยัง Trusted Publishers → Certificates

สคริปต์ PowerShell ที่ลงนามแล้วจะสามารถรันได้โดยไม่แสดงการแจ้งเตือนผู้เผยแพร่ที่ไม่น่าเชื่อถือ

เคล็ดลับ. ใบรับรองรากของ CA และใบรับรองที่ใช้ลงนามสคริปต์ ต้องได้รับความเชื่อถือ (มิฉะนั้นสคริปต์จะไม่รัน) สามารถปรับใช้ใบรับรองไปยังคอมพิวเตอร์ในโดเมนแบบรวมศูนย์ได้โดยใช้ GPO ใบรับรองต้องวางในส่วน Public Key Policies ของ GPO: Computer Configuration → Policies → Windows Settings → Security Settings → Public Key Policies → Trusted Root Certification Authorities และ Trusted Publishers

หากใบรับรองรากไม่ได้รับเชื่อถือ เมื่อรันสคริปต์ PowerShell จะเกิดข้อผิดพลาด:

A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider.

เกิดอะไรขึ้นหากแก้ไขโค้ดของสคริปต์ที่ลงนามแล้ว?

การพยายามรันจะถูกบล็อกพร้อมแจ้งเตือนว่าเนื้อหาของสคริปต์ถูกเปลี่ยนแปลง

File xx.ps1 cannot be loaded. The contents of file xx.ps1 might have been changed by an unauthorized user or process, because the hash of the file does not match the hash stored in the digital signature. The script cannot run on the specified system.

ลองตรวจสอบลายเซ็นของสคริปต์ด้วย cmdlet Get-AuthenticodeSignature หากแฮชที่คำนวณได้ไม่ตรงกับแฮชในลายเซ็น จะแสดงข้อความ HashMismatch

ดังนั้น การแก้ไขโค้ดของสคริปต์ PS1 ที่ลงนามแล้วจะต้องทำการลงนามใหม่ (re-sign) ทุกครั้ง