Как подписать файл PowerShell скрипта (ps1) с помощью сертификата?
Наличие цифровой подписи у скрипта или исполняемого файла позволяет пользователю удостовериться, что файл является оригинальным и его код не был изменен третьими лицами. В современных версиях PowerShell есть встроенные средства для подписывания кода файла скриптов *.ps1 с помощью цифровых сертификатов.
Для подписывания скриптов PowerShell нужно использовать специальный сертификат типа Code Signing. Этот сертификат может быть получен от внешнего коммерческого центра сертификации, внутреннего корпоративного Certificate Authority (CA) или можно даже самоподписанный сертификат.
Предположим, у нас в домене развернуты службы PKI — Active Directory Certificate Services. Запросите новый сертификат, перейдя на страницу
https://CA-server-name/certsrv
. Нужно запросить новый сертификат с шаблоном Code Signing (данный шаблон должен быть предварительно разрешен в консоли Certification Authority).
Также пользователь может самостоятельно запросить сертификат для подписи PowerShell скриптов из
mmc
оснастки Certificates -> My user account -> Personal -> All task -> Request New Certificate.
Если вы запросили сертификат вручную, у вас должен получится файл сертификат x509 в виде файла с расширением .cer. Данный сертификат нужно установить в локальное хранилище сертификатов вашего компьютера.
Для добавления сертификата в доверенные корневые сертификаты компьютера можно использовать следующие команды PowerShell:
$certFile = Export-Certificate -Cert $cert -FilePath C:pscertname.cer
Import-Certificate -CertStoreLocation Cert:LocalMachineAuthRoot -FilePath $certFile.FullName
Если вы хотите использовать самоподписанный сертификат, то вы можете использовать командлета New-SelfSignedCertificate чтобы создать сертификат типа CodeSigning c DNS именем test1:
New-SelfSignedCertificate -DnsName test1 -Type CodeSigning
$cert = New-SelfSignedCertificate -Subject "Cert for Code Signing” -Type CodeSigningCert -DnsName test1 -CertStoreLocation cert:LocalMachineMy
После генерации сертификата, его нужно будет в консоли управления хранилищем сертификатов (
certmgr.msc
) перенести из контейнера Intermediate в Trusted Root.
После того, как сертификат получен, можно настроить политику исполнения скриптов PowerShell, разрешив запуск только подписанных скриптов. По умолчанию PowerShell Execution политика в Windows 10/Windows Server 2016 установлена в значение Restricted. Это режим блокирует запуск любых PowerShell скриптов:
File C:pstest_script.ps1 cannot be loaded because running scripts is disabled on this system.
Чтобы разрешить запуск только подписанных PS1 скриптов, можно изменить настройку политики исполнения скриптов на AllSigned или RemoteSigned (разница между ними в том, что RemoteSigned требует наличие подписи только для скриптов, полученных из интернета):
Set-ExecutionPolicy AllSigned –Force
В этом режиме при запуске неподписанных PowerShell скриптов появляется ошибка:
File C:pstest_script.ps1 cannot be loaded. The file .ps1 is not digitally signed. You cannot run this script on the current system.
Разрешать только подписанные сценарии
” (Allow only signed scripts).
Теперь перейдем к подписыванию файла со скриптом PowerShell. В первую очередь вам нужно получить сертификат типа CodeSign из локального хранилища сертификатов текущего пользователя. Сначала выведем список всех сертификатов, которые можно использовать для подписывания кода:
Get-ChildItem cert:CurrentUsermy –CodeSigningCert
В нашем случае мы возьмем первый сертификат и сохраним его в переменную $cert.
$cert = (Get-ChildItem cert:CurrentUsermy –CodeSigningCert)[0]
Затем можно использовать данный сертификат, чтобы подписать файл PS1 с вашим скриптом PowerShell:
Set-AuthenticodeSignature -Certificate $cert -FilePath C:PStest_script.ps1
Также можно использовать такую команду (в данном случае мы вибираем самоподписанный сертификат созданный ранее по DnsName):
Set-AuthenticodeSignature C:PStest_script.ps1 @(gci Cert:LocalMachineMy -DnsName test1 -codesigning)[0]
-TimestampServer "http://timestamp.verisign.com/scripts/timstamp.dll"
.
Если вы попытаетесь использовать обычный сертификат для подписывания скрипта, появится ошибка:
Set-AuthenticodeSignature : Cannot sign code. The specified certificate is not suitable for code signing.
Get-ChildItem c:ps*.ps1| Set-AuthenticodeSignature -Certificate $Cert
Теперь можно проверить, что скрипт подписан. Можно использовать командлет Get-AuthenticodeSignature или открыть свойства PS1 файла и перейдти на вкладку Digital Signatures.
Get-AuthenticodeSignature c:pstest_script.ps1 | ft -AutoSize
Если при выполнении команды Set-AuthenticodeSignature появится предупреждение UnknownError, значит этот сертификат недоверенный, т.к. находится в персональном хранилище сертификатов пользователя.
Нужно переместить его в корневые сертификаты (не забывайте периодически проверять хранилище сертификатов Windows на наличие недоверенных сертфикатов и обновлять списки корневых сертификатов):
Move-Item -Path $cert.PSPath -Destination "Cert:LocalMachineRoot"
Теперь при проверке подписи PS1 файла должен возвращаться статус Valid.
При подписывании файла PowerShell скрипта, командлет Set-AuthenticodeSignature добавляет в конец текстового файла PS1 блок сигнатуры цифровой подписи, обрамленный специальными метками:
# SIG # Begin signature block ........... ........... # SIG # End signature block
Блок сигнатуры содержит хэш скрипта, который зашифрован с помощью закрытого ключа.
При первой попытке запустить скрипт появится предупреждение:
Do you want to run software from this untrusted publisher? File C:PStest_script.ps1 is published by CN=test1 and is not trusted on your system. Only run scripts from trusted publishers.
Если выбрать [A] Always run, то при запуске любых PowerShell скриптов, подписанных этим сертификатом, предупреждение появляться больше не будет.
Чтобы это предупреждения не появлялось нужно скопировать сертификат также в раздел Trusted Publishers. С помощью обычной операции Copy-Paste в консоли Certificates скопируйте сертификат в раздел Trusted Publishers -> Certificates.
Теперь подписанный PowerShell скрипт будет запускаться без уведомления об untrusted publisher.
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.
Что произойдет, если изменить код подписанного файла со скриптом PowerShell? Его запуск будет заблокирован, с ошибкой, что содержимое скрипта было изменено:
C:PStest_script.ps1 : File C:PStest_script.ps1 cannot be loaded. The contents of file C:PStest_script.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.
Попробуйте проверить цифровую подпись скрипта с помощью командлета
Get-AuthenticodeSignature
. Если хэш не совпадает с хэшем в подписи, появится сообщение HashMismatch.
Таким образом, после любой модификации кода подписанного PS1 скрипта его нужно заново переподписать.
Windows 10
Как подписать файл PowerShell скрипта (ps1) с помощью сертификата?