Powershell файл не имеет цифровой подписи

Обновлено: 04.07.2024

date

24.02.2021

directory

PowerShell, Windows 10, Windows Server 2016

comments

комментариев 5

Наличие цифровой подписи у скрипта или исполняемого файла позволяет пользователю удостовериться, что файл является оригинальным и его код не был изменен третьими лицами. В современных версиях PowerShell есть встроенные средства для подписывания кода файла скриптов *.ps1 с помощью цифровых сертификатов.

Для подписывания скриптов PowerShell нужно использовать специальный сертификат типа Code Signing. Этот сертификат может быть получен от внешнего коммерческого центра сертификации, внутреннего корпоративного Certificate Authority (CA) или можно даже самоподписанный сертификат.

Шаблон сертификата code signing

Также пользователь может самостоятельно запросить сертификат для подписи PowerShell скриптов из mmc оснастки Certificates -> My user account -> Personal -> All task -> Request New Certificate.

консоль certificates запросить новый сертификат

Если вы запросили сертификат вручную, у вас должен получится файл сертификат 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 скриптов:

Чтобы разрешить запуск только подписанных PS1 скриптов, можно изменить настройку политики исполнения скриптов на AllSigned или RemoteSigned (разница между ними в том, что RemoteSigned требует наличие подписи только для скриптов, полученных из интернета):

Set-ExecutionPolicy AllSigned –Force

В этом режиме при запуске неподписанных PowerShell скриптов появляется ошибка:

Разрешить выполнение подписанных скриптов PowerShell также можно с помощью параметра групповых политик Включить выполнение сценариев (Turn on Script Execution) в разделе GPO 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]

Затем можно использовать данный сертификат, чтобы подписать файл 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]

Совет. У командлета Set-AuthenticodeSignature есть специальный параметр TimestampServer, в котором указывается URL адрес Timestamp службы. Если этот параметр оставить пустым, то PS скрипт перестанет запускаться после истечения срока действия сертификата. Например -TimestampServer "http://timestamp.verisign.com/scripts/timstamp.dll" .

Если вы попытаетесь использовать обычный сертификат для подписывания скрипта, появится ошибка:

Можно подписать сразу все файлы PowerShell скриптов в папке:

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

Теперь можно проверить, что скрипт подписан. Можно использовать командлет Get-AuthenticodeSignature или открыть свойства PS1 файла и перейдти на вкладку Digital Signatures.

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

powershell скрипт с цифровой подписью

Если при выполнении команды Set-AuthenticodeSignature появится предупреждение UnknownError, значит этот сертификат недоверенный, т.к. находится в персональном хранилище сертификатов пользователя.

Set-AuthenticodeSignature UnknownError

Теперь при проверке подписи PS1 файла должен возвращаться статус Valid.

используем командлет Set-AuthenticodeSignature чтобы подписать файл с powershell скриптом

При подписывании файла PowerShell скрипта, командлет Set-AuthenticodeSignature добавляет в конец текстового файла PS1 блок сигнатуры цифровой подписи, обрамленный специальными метками:

Блок сигнатуры содержит хэш скрипта, который зашифрован с помощью закрытого ключа.

При первой попытке запустить скрипт появится предупреждение:

Если выбрать [A] Always run, то при запуске любых PowerShell скриптов, подписанных этим сертификатом, предупреждение появляться больше не будет.

ps1 is published by CN=test1 and is not trusted on your system. Only run scripts from trusted publishers

Чтобы это предупреждения не появлялось нужно скопировать сертификат также в раздел Trusted Publishers. С помощью обычной операции Copy-Paste в консоли Certificates скопируйте сертификат в раздел Trusted Publishers -> Certificates.

скопировать сертфика codesigning в Trusted Publishers

Теперь подписанный PowerShell скрипт будет запускаться без уведомления об untrusted publisher.

Совет. Корневой сертификат CA и сертификат, которым подписан скрипт, должен быть доверенным (иначе скрипт вообще не запустится). Вы можете централизованно установить сертификаты на все компьютеры домена с помощью GPO. Сертфикаты нужно поместить в следующие разделы GPO:

Computer Configuration -> Policies -> Windows Settings -> Security Settings -> Public Key Policies -> Trusted Root Certification Authorities и Trusted Publishers.

Если корневой сертификат недоверенный, то при запуске скрипта PowerShell будет появляться ошибка:

Что произойдет, если изменить код подписанного файла со скриптом PowerShell? Его запуск будет заблокирован, с ошибкой, что содержимое скрипта было изменено:

ошибка при запуске модифицированного powershell скрипта The contents of file have been changed

Get-AuthenticodeSignature ошибка HashMismatch

Таким образом, после любой модификации кода подписанного PS1 скрипта его нужно заново переподписать.


По умолчанию выполнение сценариев Windows PowerShell в системе запрещено. По соображениям безопасности все скрипты PowerShell должны быть подписаны цифровой подписью, данный метод называется - политика выполнения.

Если скрипт не соответствует этому условию, то выполнение сценариев PowerShell в системе запрещено. Это связано в первую очередь с тем, что в скрипте может находиться вредоносный код, который может нанести вред операционной системе.

PowerShell имеет несколько режимов выполнения, которые определяют, какой тип кода разрешается выполнять. Существует 5 различных режимов выполнения:

  1. Ограниченный (Restricted) — значение по умолчанию. Блокируется выполнение любых скриптов и разрешается работа интерактивных команд.
  2. Все подписанные (All Signed) — разрешено выполнение скриптов, имеющих цифровую подпись.
  3. Удаленные подписанные (Remote Signed) — локальные скрипты работают без подписи. Все скачанные скрипты должны иметь цифровую подпись.
  4. Неограниченный (Unrestricted) — разрешено выполнение любых скриптов. При запуске не подписанного скрипта, который был загружен из Интернета, программа может потребовать подтверждение.
  5. Обходной (Bypass) — ничего не блокируется, никакие предупреждения и запросы не появляются.

Самым безопасным способом решения этой проблемы является – изменение политики выполнения на неограниченную, запуск скрипта, и затем обратный возврат к ограниченной политике.

Для изменения политики выполнения на неограниченную, воспользуемся консолью PowerShell открытую с правами Администратора и выполним следующую команду:

После запуска команды вам будет предложено подтвердить изменение политики выполнения. Ответим Y ( Да ).

Теперь можно запустить скрипт. Однако, вы подвергаете систему серьезному риску, так что по окончании работы скрипта, не забудьте вернуть политику выполнения назад в ограниченный режим. Сделать это можно с помощью следующей команды:

После запуска команды вам будет предложено подтвердить изменение политики выполнения. Ответим Y ( Да )

Далее ниже представлены все команды для изменения политики выполнения.

Блокируется выполнение любых скриптов. Значение по умолчанию.

Разрешено выполнение скриптов, имеющих цифровую подпись.

Скрипты, подготовленные на локальном компьютере, можно запускать без ограничений, скрипты, загруженные из Интернета - только при наличии цифровой подписи.

Разрешено выполнение любых скриптов. При запуске не подписанного скрипта, который был загружен из Интернета, программа может потребовать подтверждение.

Ничего не блокируется, никакие предупреждения и запросы не появляются.

Для выполнения выше представленных команд без подтверждения изменения, воспользуйтесь параметром -Force , например выполните команду:

Теперь при выполнении команд не нужно подтверждать производимые изменения.

При разработке PowerShell особое внимание было уделено безопасности. Одной из мер безопасности является наличие политики выполнения (Execution Policy), которая определяет, могут ли скрипты PowerShell выполняться в системе, и если могут, то какие именно.

Это сработала политика выполнения, и если мы все же хотим выполнить скрипт, то ее необходимо изменить. Выбрать можно одно из следующих значений:

Теоретически все понятно, проверим на практике. Для просмотра параметров политики используется командлет Get-ExecutionPolicy, а для изменения Set-ExecutionPolicy.

Для начала выведем действующую политику выполнения командой:

Как и ожидалось, текущая политика Restricted. Разрешим выполнение скриптов, установив для политики значение Unrestricted:

Set-ExecutionPolicy Unrestricted -Force

И еще попробуем запустить скрипт. На сей раз он выполнился без ошибок.

изменение политики выполнение на Unrestricted

Политика Unrestricted разрешает выполнение любых скриптов, но у нее все же есть ограничения. Для проверки я подготовил два скрипта, локальный localscript.ps1 и удаленный remotescript.ps1. Сначала запустим локальный, он выполнится без проблем. А вот при запуске удаленного скрипта PowerShell выдаст предупреждение и потребует подтвердить его запуск. При ручном выполнении это не является большой проблемой, а вот в случае автоматического запуска (напр. из планировщика) скрипт может не отработать.

выполнение локального и удаленного скрипта

установка политики выполнения Bypass

Следующим пунктом нашего меню идет политика RemoteSigned. Она является наиболее сбалансированной как с точки зрения безопасности, так и удобства использования, поэтому на серверах включена по умолчанию. Установим для политики значение RemoteSigned и проверим ее действие. Локальный скрипт снова выполняется без проблем, а удаленный выдает ошибку, поскольку у него нет подписи.

установка политики выполнения RemoteSigned

У вас может возникнуть вопрос, как именно PowerShell различает локальные и удаленные скрипты. Тут все просто. При загрузке файла приложение (напр. браузер) добавляет файл идентификатор зоны (ZoneId), который и определяет, откуда был взят файл. Идентификатор хранится в альтернативном потоке и имеет значение от 0 до 4:

• Локальный компьютер (0)
• Местная сеть (1)
• Надежные сайты (2)
• Интернет (3)
• Опасные сайты (4)

Если файл имеет ZoneId 3 или 4, то PowerShell считает его удаленным. А если на компьютере включена конфигурация усиленной безопасности Internet Explorer, то файлы, взятые из локальной сети, тоже могут считаться удаленными.

Как выполнить удаленный скрипт? Во первых его можно разблокировать (превратить в локальный), для этого есть специальный командлет Unblock-File. Хотя если просто открыть скрипт на локальном компьютере и внести в него изменения, то он тоже станет локальным.

выполнение подписанного скрипта

Переходим к политике AllSigned. Это наиболее жесткая политика, требующая подписывания всех без исключения скриптов, как удаленных так и локальных. И даже с подписанными скриптами она работает не так, как RemoteSigned. Для примера сменим политику на AllSigned и снова запустим подписанный скрипт. В этот раз для его выполнения потребуется подтверждение, т.к. PowerShell посчитал подпись недоверенной.

запрос на выполнение подписанного скрипта

Области применения

Политика выполнения имеет свою область действия (scope). Всего есть 5 областей:

Вывести значение политики для всех областей можно командой:

Области действия политики выполнения

Получается, что при установке политики без указания области изменяется значение LocalMachine. Если же требуется указать конкретную область действия, то сделать это можно с помощью параметра Scope командлета Set-ExecutionPolicy. Для примера установим для области СurrentUser политику Bypass:

Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Bypass -Force

Затем проверим значение политики в текущем сеансе и убедимся в том, что оно изменилось на Bypass.

изменяем политику выполнения для текущего пользователя

Теперь установим политику Unrestricted для области Process:

Set-ExecutionPolicy -Scope Process -ExecutionPolicy Unrestricted -Force

Еще раз проверим текущую политику, теперь она имеет значение Unrestricted. Т.е. более ″конкретная″ политика всегда имеет больший приоритет.

изменяем политику выполнения для процесса

групповые политики PowerShell

Для установки политики надо включить параметр и выбрать одно из трех значений:

Политика Bypass считается небезопасной и ее нельзя установить через групповые политики.

Установка политики выполнения через GPO

Для примера установим для MachinePolicy политику RemoteSigned и проверим результат. Как видите, политика, назначенная через GPO, имеет больший приоритет и переопределяет все остальные политики.

список политик выполнения по областям

Более того, при использовании GPO становится невозможным переназначить политики вручную. При попытке изменения выдается предупреждение, а текущая политика остается без изменений.

попытка изменения политики выполнения

А что будет, если ни для одной области политика не определена, т.е. везде стоит значение Undefined? В этом случае все просто, выполнение всех скриптов запрещается, а текущая политика принимает значение Restricted.

политика Undefined

Обход политики

Можно ли как то запустить скрип в обход политики выполнения, не изменяя ее значение? В принципе можно, есть несколько способов.

К примеру для того, чтобы выполнить скрипт, достаточно открыть его в проводнике, кликнуть правой клавишей мыши и выбрать пункт Выполнить с помощью PowewrShell (Run with PowerShell). Это запускает оболочку PowerShell c политикой Bypass. При этом политика применяется только для выполнения конкретного скрипта, значение политики в реестре не изменяется.

выполнение скрипта PowerShell из проводника

Собственно говоря, предыдущий способ использует запуск PowerShell с указанием требуемой политики. Сделать это можно из командной строки, например для запуска скрипта можно попробовать такую команду:

powershell.exe -file .\script.ps1 -Executionpolicy Bypass

Теоретически эта команда должна выполнить скрипт, не смотря на текущую политику. Так написано в официальной документации Microsoft. На практике же этот способ работает не всегда, например на одном из проверенных мной компьютеров я получил ошибку. При этом из проводника скрипт успешно выполнился.

ошибка при использовании политики Bypass

Ну и наконец можно просто считать содержимое скрипта и выполнить его в виде команды. Например так:

При решении одной конкретной задачи автору довелось работать с данной оболочкой автоматизации, не имея особого опыта взаимодействия с ней. На написание скрипта ушло не более получаса, но по большому счету назвать его скриптом можно было с натяжкой, так как прописанный набор инструкций был непригодным для выполнения в виде скрипта в PowerShell.

Решаем проблему с подписью скрипта в Powershell

Проблема здесь заключается в том, что для выполнения скрипта существуют некоторые ограничения, которые задаются в рамках политики скриптового исполнения. Таким образом, при создании скрипта его мгновенное выполнение на рабочей машине оказалось попросту невозможным. Если мы говорим о рабочем сервере, то проблема, которая решается для локального компьютера изменением настроек политики исполнения на RemoteSigned или Unresricted, в данном случае является более серьезной.

Вполне логично, что готовый исполняемый скрип требует подписи. Способ, который был использован автором для того, чтобы организовать механизм подписи для скрипта, надо сказать, достаточно тернист. Тем не менее, усилия стоили того, и теперь автор спешит поделиться собственным опытом организации такого механизма с нашими читателями.

Как решить проблему подписи?

Начнем с того, что по дефолту на исполнение любых скриптов наложен запрет. И потому для начала нам потребуется разрешить выполнение скриптов только от доверенных издателей, с соответствующим корневым сертификатом. Прописываем из под сеанса админа в PowerShell следующее:

> Sеt-ExecutiоnPоliсy АllSignеd

Теперь придется повозиться с утилитой для создания персонального и корневого сертификатов. В соответствии с «инструкцией»

> Gеt-Hеlp Abоut_Signing

для создания сертификата используется утилита mekecert.exe, которая находится здесь:

%Prоgram Filеs%\Micrоsoft SDKs\Windоws\v7.0A\bin\mаkесеrt

Дальнейшие манипуляции, прописанные ниже, необходимо выполнить под обычным сеансом командной строки:

Для начала создаем корневой сертификат, который будет использовать локальную машину в качестве центра его удостоверения:

> mаkecеrt -n "CN=PоwеrShеll Lоcal Cеrtificаte Rооt" -a shа1 -еku 1.3.6.1.5.5.7.3.3 -r -sv rооt.рvk rооt.cеr -ss Rооt -sr lосаlMасhinе

Данный способ «бесплатного» получения сертификата используется достаточно часто и считается одним из наиболее практичных.

Теперь создаем персональный пользовательский сертификат дл PowerShell.

> mаkecert -pе -n "CN=PоwеrShеll Usеr" -ss MY -а shа1 -еku 1.3.6.1.5.5.7.3.3 -iv rооt.pvk -ic rооt.cеr

С его помощью будут подписываться скрипты при использовании корневого сертификата для его заверения. При успешном выполнении всех манипуляций в обеих строках должно отобразиться состояние « Succeeded ».

При наличии персонального сертификата X509 можно не выполнять манипуляции, которые были описаны выше. Далее проверяем, что ОС распознает сертификат, который мы только что создали. Для этого в Powershell прописываем:

> Gеt-Сhilditеm cеrt:\СurrеntUsеr\my –cоdеsigning

В принципе вы уже имеете возможность подписывать скрипты, но с необходимостью дописывать следующую строку для подписи в PowerShell:

> Sеt-AuthеnticоdeSignature "FilеNаmе" @(Gеt-ChildItеm cert:\CurrеntUsеr\Mу -cоdesigning)[0]

Вполне логично создать скрипт, подписывающий другие скрипты, который можно создать в любом текстовом редакторе, исключая ISE PowerShell. Скрипты, создаваемые в рамках данной среды, могут словить ошибку по типу «Unknown Error».

Скрипт, который нас интересует в данном случае, будет выглядеть так:

pаram([string] $file=$(thrоw "Plеаse spеcify а filеname."))

$cеrt = @(Gеt-ChildItеm cеrt:\CurrеntUsеr\My -cоdеsigning)[0]

Sеt-AuthеnticоdeSignаture $filе $cеrt

Примечания

- Если корневой сертификат на любом компьютере, кроме того, на котором он был создан, не достоверный, скрипт не удастся выполнить в принципе;

- Персональный сертификат издателя при тех же условиях, что и в предыдущем положении, скрипт можно будет выполнить с необходимостью подтверждения.

Для добавления обоих типов сертификатов в список достоверных потребуется использовать консоль mmc (оснастка Cеrtificates). Необходимо добавить сертификаты в папки Trustеd Publishеrs и Trustеd Rооt Cеrtification Authorities.

Читайте также: