Signering av PowerShell-skript
I ❤️ PowerShell. Det är ett riktigt användbart verktyg för att automatisera de uppgifter som du gör flera gånger. Men det kan också vara ett gapande säkerhetshål om du låter det göra det.
PowerShell gör det möjligt för dig att administrera nästan allt på din maskin, så det finns mycket skada som skulle kunna göras av någon som kan köra skadliga skript i dina miljöer.
Förut var det begränsat till enbart Windows, men sedan version 6 och nu i och med lanseringen av PowerShell 7.0 kan det även användas på Linux och MacOS. Den här artikeln handlar dock om Execution Policies som inte kan ändras i andra miljöer än Windows-miljöer och som därför inte är till någon nytta för Linux/MacOS-användare (tyvärr).
Execution Policies
Ett sätt att begränsa möjligheten att köra skript i dina Windows-miljöer är att använda PowerShells exekutionsprinciper. Tldr är att de kan användas för att begränsa de skript som kommer att köras i miljön. De tillgängliga alternativen från minst säker till mest säker är:
Bypass
Inget blockeras.
Obegränsad (gäller alltid på maskiner som inte är Windows-maskiner)
Samma som ByPass
men frågar användaren innan han/hon kör skript från internet.
RemoteSigned (standard för Windows-servrar)
Skripter som har laddats ner från internet kan endast köras om de är signerade. Skript som skrivits på maskinen kan köras
AllSigned
Alla skript måste signeras innan de kan köras
Restricted (standard för Windows-klienter)
Förhindrar att skript körs. Kan endast köra enskilda kommandon.
Kör skript
Så du vill köra dina egna PowerShell-skript på din server. Men du får en PSSecurityException
som följande.
PS C:\Users\Administrator\Downloads> .\wibble.ps1.\wibble.ps1 : File .\wibble.ps1 cannot be loaded. The file.\wibble.ps1 is not digitally signed. You cannot run this script on the current system.For more information about running scripts and setting execution policy, see about_Execution_Policies athttp://go.microsoft.com/fwlink/?LinkID=135170.At line:1 char:1+ .\wibble.ps1+ ~~~~~~~~~~~~ + CategoryInfo : SecurityError: (:) , PSSecurityException + FullyQualifiedErrorId : UnauthorizedAccess
Ett sätt att lösa problemet är att ändra exekveringspolicyn med hjälp av kommandot Set-ExecutionPolicy
och minska säkerheten på maskinen. Detta är i allmänhet en dålig idé.
Personligen skulle jag aldrig använda något mindre säkert än RemoteSigned
på en server, men AllSigned
helst.
Vad är en skript-signatur?
Förmodligen vill du bibehålla maskinens säkerhet och inte öppna en sårbarhet, så det alternativ som återstår för dig är att signera dina skript.
Signering av ett skript innebär att någon med tillgång till den privata nyckeln för ett kodsigneringscertifikat har lagt till ett signaturblock i slutet av skriptfilen.
function Get-Wibble { return "Wibble"}# SIG # Begin signature block# vpnIUpm2XxLRhU1no0iuA62xKxYzR6m95z9Ax21ppeTC9NoRd8ocoSGr1zAd# qlMOlz4lZoVWR4ZmtdCgzde1dVxzv4jjHb6ziDiY2o05UXswD2bl6XaOrUpd# Li0Qjg3d3y2r1nrpO8hos906bgXQswysvouegUJcpt8ftmqBKfEYNeBgnBFm# SIG # End signature block
(Endast exempel. Signaturblocket är vanligtvis mycket längre)
Signaturblocket kommer att innehålla en hash av skriptet som har krypterats med den privata nyckeln. När man försöker köra skriptet dekrypteras detta med hjälp av den offentliga nyckeln och jämförs med den faktiska hashen. Om det stämmer överens kan vi bekräfta att skriptet inte har manipulerats eftersom hashkoden skulle ändras så snart det sker.
Självsigneringscertifikat
Om dina skript endast kommer att köras av maskiner i din organisation kommer du troligen att kunna självsignera certifikaten. Alternativet är att spendera $$$$ och köpa ett kodsigneringscertifikat varje år.
Självsignering innebär att du genererar certifikatet själv och signerar skripten med hjälp av det.
Hur man skapar ett självsigneringscertifikat
PowerShell har det mycket användbara kommandot New-SelfSignedCertificate
för att producera självsignerade certifikat. Vi kan sedan exportera dem och placera dem i olika butiker.
Som standard skapar kommandot ett certifikat som löper ut efter 1 år. Du kan ändra detta genom att använda parametern -NotAfter
och ange det datum du vill att certifikatet ska löpa ut.
För att skapa ett certifikat startar du en PowerShell-session och kör följande
$CertificateName = Read-Host "Input your certificate name"$OutputPFXPath = "$CertificateName.pfx"$OutputCERPath = "$CertificateName.cer"$Password = Get-Credential -UserName Certificate -Message "Enter a secure password:"$certificate = New-SelfSignedCertificate -subject $CertificateName -Type CodeSigning -CertStoreLocation "cert:\CurrentUser\My"$pfxCertificate = Export-PfxCertificate $certificate -FilePath $OutputPFXPath -password $Password.passwordExport-Certificate -Cert $certificate -FilePath $OutputCERPathImport-PfxCertificate $pfxCertificate -CertStoreLocation cert:\CurrentUser\Root -Password $password.passwordWrite-Output "Private Certificate '$CertificateName' exported to $OutputPFXPath"Write-Output "Public Certificate '$CertificateName' exported to $OutputCERPath"
Detta kommer att skapa certifikatet och exportera det till två separata filer med tillägg .pfx
och .cer
.
PFX
PFX-certifikatet är det som måste installeras på de maskiner som ska utföra signeringen. I vårt fall är det var och en av våra utvecklare.
Det ska installeras i cert:\CurrentUser\Root
-lagret, även känt som ”Trusted Root Certification Authorities”-lagret.
Denna fil ska förvaras på en säker plats. Lösenordet bör sedan säkras separat (använd en lösenordshanterare). Om en dålig aktör får tag på båda dessa kan de signera sina skadliga skript som om de vore du.
CER
Den CER-certifikatsfilen är det du måste installera på de maskiner som ska köra skripten. Den kräver inget lösenord för att installeras men kan inte användas för att signera skript. Den innehåller endast den offentliga nyckeln som används för att dekryptera signaturen.
Då den inte innehåller den privata nyckeln kan det här certifikatet distribueras fritt till alla miljöer som kommer att köra skripten.
Detta kommer att behöva installeras i två certifikatarkiv på maskinerna som kommer att köra skripten; cert:\LocalMachine\Root
och cert:\LocalMachine\TrustedPublisher
-lagren.
Signering av skript
Funktionen Set-AuthenticodeSignature
tillhandahålls för att signera skript. Vi måste skicka in sökvägen till skriptet och certifikatet från lagret. Vi har skrivit en omslagsfunktion som kan signera skript.
function Set-ScriptSignatures { param ( $pathToScripts = "." ) $certificateName = "PowerShell Signing Certificate" $scripts = Get-ChildItem -Path "$pathToScripts\*" -Include *.ps1, *.psm1 -Recurse $certificate = @(Get-ChildItem cert:\CurrentUser\My -codesign | Where-Object { $_.issuer -like "*$certificateName*" } ) foreach ($script in $scripts) { Write-Host "Signing $script" Set-AuthenticodeSignature $script -Certificate $certificate }}
Variabeln $certificateName
ska innehålla det namn som användes när certifikatet skapades.
Du kan använda funktionen genom att ange en sökväg till katalogen som innehåller skripten och den kommer att gå igenom dem och signera dem alla.
När du har installerat skripten på målmaskinen bör du nu kunna köra skripten utan några problem.