PowerShell-scripts ondertekenen
Ik ❤️ PowerShell. Het is een heel handig hulpmiddel voor het automatiseren van taken die je meerdere keren uitvoert. Maar het kan ook een gapend veiligheidslek zijn als je het toelaat.
Met PowerShell kun je bijna alles op je machine beheren, dus er kan veel schade worden aangericht door iemand die kwaadaardige scripts in je omgevingen kan uitvoeren.
Voorheen beperkt tot alleen Windows, sinds versie 6 en nu met de release van PowerShell 7.0, kan het ook worden ingezet op Linux en MacOS. Dit artikel heeft het echter over Execution Policies, die niet kunnen worden gewijzigd in niet-Windows-omgevingen, dus Linux/MacOS-gebruikers hebben er niets aan (sorry).
Execution Policies
Eén manier waarop u de mogelijkheid om scripts uit te voeren in uw Windows-omgevingen kunt beperken, is door het gebruik van PowerShell’s uitvoeringsbeleid. De tldr is dat ze kunnen worden gebruikt om de scripts die in de omgeving worden uitgevoerd te beperken. De beschikbare opties, van minst veilig tot meest veilig, zijn:
Bypass
Niets wordt geblokkeerd.
Unrestricted (Altijd van toepassing op Non-Windows machines)
Hetzelfde als ByPass
maar vraagt de gebruiker voordat hij scripts vanaf het internet uitvoert.
RemoteSigned (standaard voor Windows Servers)
Scripts die zijn gedownload van het internet kunnen alleen worden uitgevoerd als ze zijn ondertekend. Scripts die op de machine zijn geschreven kunnen worden uitgevoerd
AllSigned
Alle scripts moeten zijn ondertekend voordat ze kunnen worden uitgevoerd
Restricted (standaard voor Windows-clients)
Voorkomt dat scripts worden uitgevoerd. Kan alleen individuele commando’s uitvoeren.
Scripts uitvoeren
U wilt dus uw eigen PowerShell-scripts op uw server uitvoeren. Maar u krijgt een PSSecurityException
zoals de volgende.
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
Eén manier om dit probleem op te lossen is om het uitvoeringsbeleid te wijzigen met de opdracht Set-ExecutionPolicy
en de beveiliging van de machine te verminderen. Dit is over het algemeen een slecht idee.
Persoonlijk zou ik nooit iets gebruiken dat minder veilig is dan RemoteSigned
op een server, maar AllSigned
zou ideaal zijn.
Wat is een script handtekening?
Aannemelijk is dat je de beveiliging van de machine wilt handhaven en geen kwetsbaarheid wilt openen, dus de optie die je overhoudt is om je scripts te ondertekenen.
Het ondertekenen van een script betekent dat iemand met toegang tot de privésleutel voor een code-signeercertificaat een blok handtekeningen aan het einde van het scriptbestand heeft toegevoegd.
function Get-Wibble { return "Wibble"}# SIG # Begin signature block# vpnIUpm2XxLRhU1no0iuA62xKxYzR6m95z9Ax21ppeTC9NoRd8ocoSGr1zAd# qlMOlz4lZoVWR4ZmtdCgzde1dVxzv4jjHb6ziDiY2o05UXswD2bl6XaOrUpd# Li0Qjg3d3y2r1nrpO8hos906bgXQswysvouegUJcpt8ftmqBKfEYNeBgnBFm# SIG # End signature block
(Alleen als voorbeeld. Het blok met handtekeningen is meestal veel langer)
Het blok met handtekeningen bevat een hash van het script dat is gecodeerd met de privésleutel. Wanneer geprobeerd wordt het script uit te voeren, wordt dit gedecodeerd met de openbare sleutel en vergeleken met de eigenlijke hash. Als deze overeenkomt, kunnen we bevestigen dat er niet met het script is geknoeid, omdat de hash zou veranderen zodra dat zou gebeuren.
Zelfondertekenende certificaten
Als uw scripts alleen zullen worden uitgevoerd door machines in uw organisatie, dan zult u waarschijnlijk in staat zijn om de certificaten zelf te ondertekenen. Het alternatief is om $$$ uit te geven en elk jaar een code signing certificaat te kopen.
Self signing betekent dat u zelf het certificaat genereert en de scripts daarmee ondertekent.
Hoe maak je een self signing certificaat
PowerShell heeft het zeer nuttige New-SelfSignedCertificate
commando voor het produceren van self signed certificaten. We kunnen ze dan exporteren en in verschillende stores plaatsen.
Het commando maakt standaard een certificaat aan dat na 1 jaar verloopt. U kunt dit wijzigen met de parameter -NotAfter
en de datum opgeven waarop het certificaat moet verlopen.
Om een certificaat te maken, start u een PowerShell-sessie en voert u het volgende uit
$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"
Hiermee wordt het certificaat gemaakt en geëxporteerd naar twee afzonderlijke bestanden met de extensies .pfx
en .cer
.
PFX
Het PFX-certificaat is het certificaat dat moet worden geïnstalleerd op de machines waarop de handtekeningen moeten worden gezet. In ons geval is dat elk van onze ontwikkelaarsmachines.
Het moet worden geïnstalleerd in de cert:\CurrentUser\Root
store, ook bekend als de “Trusted Root Certification Authorities” store.
Dit bestand moet ergens veilig worden bewaard. Het wachtwoord moet apart worden beveiligd (gebruik een wachtwoordbeheerder). Als een kwaadwillende beide in handen krijgt, kan hij zijn schadelijke scripts ondertekenen alsof hij jou is.
CER
Het CER-certificaatbestand moet worden geïnstalleerd op de machines waarop de scripts zullen worden uitgevoerd. Er is geen wachtwoord nodig om dit te installeren, maar het kan niet worden gebruikt om scripts te ondertekenen. Het bevat alleen de publieke sleutel die wordt gebruikt om de handtekening te decoderen.
Omdat het geen private sleutel bevat, kan dit certificaat vrij worden verspreid naar alle omgevingen waar de scripts zullen draaien.
Dit moet in twee certificaat-opslagplaatsen worden geïnstalleerd op de machines waar de scripts zullen draaien; De cert:\LocalMachine\Root
en cert:\LocalMachine\TrustedPublisher
opslagplaatsen.
Een script ondertekenen
De Set-AuthenticodeSignature
functie is voorzien om de scripts te ondertekenen. We moeten het pad naar het script en het certificaat van de winkel invoeren. We hebben een wrapper-functie geschreven die de scripts kan ondertekenen.
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 }}
De variabele $certificateName
moet de naam bevatten die is gebruikt bij het maken van het certificaat.
U kunt de functie gebruiken door een pad op te geven naar de directory die de scripts bevat en hij zal ze allemaal ondertekenen.
Als u de scripts op de doelmachine hebt geïnstalleerd, zou u de scripts nu zonder problemen moeten kunnen uitvoeren.