Наличие цифровой подписи у скрипта или исполняемого файла позволяет пользователю удостовериться, что файл является оригинальным и его код не был изменен третьими лицами. В современных версиях 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:\ps\certname.cer
Import-Certificate -CertStoreLocation Cert:\LocalMachine\AuthRoot -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:\LocalMachine\My
После генерации сертификата, его нужно будет в консоли управления хранилищем сертификатов (
certmgr.msc
) перенести из контейнера Intermediate в Trusted Root.
После того, как сертификат получен, можно настроить политику исполнения скриптов PowerShell, разрешив запуск только подписанных скриптов. По умолчанию PowerShell Execution политика в Windows 10/Windows Server 2016 установлена в значение Restricted. Это режим блокирует запуск любых PowerShell скриптов:
File C:\ps\test_script.ps1 cannot be loaded because running scripts is disabled on this system.
Чтобы разрешить запуск только подписанных PS1 скриптов, можно изменить настройку политики исполнения скриптов на AllSigned или RemoteSigned (разница между ними в том, что RemoteSigned требует наличие подписи только для скриптов, полученных из интернета):
Set-ExecutionPolicy AllSigned –Force
В этом режиме при запуске неподписанных PowerShell скриптов появляется ошибка:
File C:\ps\test_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:\CurrentUser\my –CodeSigningCert
В нашем случае мы возьмем первый сертификат и сохраним его в переменную $cert.
$cert = (Get-ChildItem cert:\CurrentUser\my –CodeSigningCert)[0]
Затем можно использовать данный сертификат, чтобы подписать файл PS1 с вашим скриптом PowerShell:
Set-AuthenticodeSignature -Certificate $cert -FilePath C:\PS\test_script.ps1
Также можно использовать такую команду (в данном случае мы вибираем самоподписанный сертификат созданный ранее по DnsName):
Set-AuthenticodeSignature C:\PS\test_script.ps1 @(gci Cert:\LocalMachine\My -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:\ps\test_script.ps1 | ft -AutoSize
Если при выполнении команды Set-AuthenticodeSignature появится предупреждение UnknownError, значит этот сертификат недоверенный, т.к. находится в персональном хранилище сертификатов пользователя.
Нужно переместить его в корневые сертификаты (не забывайте периодически проверять хранилище сертификатов Windows на наличие недоверенных сертфикатов и обновлять списки корневых сертификатов):
Move-Item -Path $cert.PSPath -Destination "Cert:\LocalMachine\Root"
Теперь при проверке подписи 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:\PS\test_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:\PS\test_script.ps1 : File C:\PS\test_script.ps1 cannot be loaded. The contents of file C:\PS\test_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 скрипта его нужно заново переподписать.
Можно ли использовать этот способ для подписания exe-files?
Что интересно, exe, dll и другие подобные типы файлов тоже подписываются:
Set-AuthenticodeSignature C:\PS\pngcheck.exe @(gci Cert:\LocalMachine\My -DnsName test1 -codesigning)[0]
Т.е. утилита signtool теперь не нужна
Смысл? ЕХЕ выполняется в любом случае.
Можно разрешить запуск подписанных приложений по издателю через AppLocker или WDAC ( настройка Windows Defender Application Control)
Если сервер без доступа в инет будет ли работать для него TimestampServer ?
ок скрипт подписан, что мне мешает скопировать подпись и подписать свой скрипт ?
в подписи хранится чексумма (хэш) кода скрипта. если изменится хоть один символ, интерпретатор скажет что подпись не валидна
и да и нет
я поискал ответ на свой вопрос, более менее грамотно он звучит следующим образом :
при создании некоего сферического коня по имени «подпись» создаются два объекта
приватный ключик ( ключик хозяина, имея который можно генерировать новые подписи(генерировать мусор с признаком того что это сделано мастер ключем) )
паблик ключик ( ключик в котором заложено свойство «только для просмотра»)
и вот именно это и не позволит сделать «скопировать» или «переподписать» объект без этого самого мастер ключа.
Вообще извиняюсь за каламбур, причина была в том что просто переклинило и не учел принципы сертификации
Добрый день, спасибо за статью, но возникло пару вопросов:
Почему надо свой сертификат добавлять в Trusted Publishers если там уже есть сертификат издающего CA который выдал мне сертификат подписи скриптов?
А если у нас несколько людей пишут скрипты нужно сертификат каждого добавлять получается?
Если самоподписанные сертфикаты генерятся на каждом компьюетере, придется копировать.
Если есть общий CA, то только сертификат CA
простите за глупый вопрос. А если нужно подписать скрипты которые выполняются по шедуллеру, то как правильно это всё организовать? Так как скрипты эти копируются (из шары) в папку, например, TEMP у юзеров, то для централизованного управления нужно:
1. Издать на PKI сертификат Code Signing (как я понял это именно пользовательский серт, а не машинный)
2. Получить сертификат и экспортировать его
3. GPO c добавлением сертификата Code Signing в Trusted Publishers (Computer Configuration-Policies-Windows Settings-Public Key Policies-Trusted Publishers-Import.). Добавить экспортированый сертификат в эту GPO. Но тут я не понял, так как сертификат пользовательский, с указанем имени пользователя, не помешает ли это подписыванию скриптов (тоесть на все компьютеры разольётся политика с сертификатом user1, например)
3. GPO политику по запуску Allow only signed scripts
4. GPO по запуску скрипта Computer Configuration -> Policies -> Windows Settings -> Scripts (Startup / Shutdown), а в скрипте прописать подписывание ps сертификатом тем из пункта 2?
а если не так, то буду благодарен за наводку
тупо на память так что могу что-то упустить :
1. инициатер должен обладать правьями на запуск файла
2. машинка и инициатер должны иметь доступ до файлегов
3. машинка должна знать что файлег подписан красивой подписью
4. красивая подпись должна находиться в красивом контейнере для всяких сурйозных подписей( какой то там корневой чего-то или доверенный . ащпе не помню)
5. все инструкции в файлеге должны иметь возможность быть выполнены от лица инициирующего свистопляску на момент события.
6. существуют конструктивные особенности которые кудряво реализуются по тем или иным причинам, так или иначе связанным с безопасностью, для теста используйте примитивные конструкции и если что-то пошло не так и ваш цирк с пьяными котятами не завелся, то скорее всего нужно либо котят поменять либо котята с кем-то закусились.
У нас есть пачка скриптов, которые разливаются GPO и выполняются юзерам, по шедуллеру. Скриптты берутся с шары и заливаются юзерам локально в папку ТЕМП. И задача стоит подписать только их и настроить контроль над изменениями. Это в общем такая задача…
1) Сертификат для компьютера, а не для пользователя.
4) Вы хотите чтобы сертификат подписывался сразу перез запуском через GPO. Не пойму за чем так. По идее владелец скрипта (администратора) должен вручную подписать сертификат при любом изменении кода скрипта (т.е. подписанные скрипты уже лежат в вашей шаре, откуда различаются пользователям).
Или у вас скрипты динамические и формируются каждый раз заново?
В остальном все правильно описано.
1) хм… просто темплейт Code Signing доступен только для юзеров. Или я не понял тогда какой темплейт использовать
4) Хочу, что бы уже подписаные скрипты попадали юзерам на тачки и эти скрипты выполнялись ,как и раньше.
Дело в том ,что у нас есть пачка скриптов которые выполняются по шедуллерам. Сами скрипты лежат на шаре на домен контроллере, юзеру залетают по политике (копируются с шары и кладутся в папку C\Windows\Temp, Action — Update )
Я просто думал так, подписываю сертификатом данные скрипты на шаре, юзерам раскидываю мой сертификат Code Signing в Trusted Publishers и включаю политику Allow only signed scripts.
И таким образом каждый раз когда юзер будет с шары получать скрипты, он уже будет их подписанными получать и так как имея сертификат Code Signing не будет проблем с выполнением.
Очень буду благодарен, если тапками не закидаете и подскажите, всё ли я правильно думаю? по темплейту серта наверное не до конца ясно.
Как я понял, у вас используется собственный CA на Windows.
В этом случае, и его сертификат уже распространен на клиенты? В этом случае вам сертификат подписан корневым CA и является доверенным и его не нужно комипроть пользователям повторно.
В остальном вся логика правильная.
Как всегда инструкция на высшем уровне, большое Вам спасибо!
Но как всегда не на 100% гладко всё прошло, в моё случае сертификат нужно было разместить в папке Доверенный издатель, только после этого подписанный скрипт отрабатывал без единого вопроса и как нужно.
А ещё было бы не плохо сделать инструкцию как поднять и настроить AD CS, чтобы перейти по ссылке _https://CA-server-name/certsrv и выпустить сертификат. Нашёл стороннюю инструкцию, то там много «опечаток», по инструкции одно, на самом деле нужно делать по другому. В итоге дошёл до того, что страница начала открываться, проходить авторизация, но выпустить толком сертификат не получается, так как много конфигурационных моментов пустые и ни чего не выбрать.