Введение
Если при работе в PowerShell вы заметили, что строки с токенами или другими секретными значениями исчезают из истории после закрытия сессии — это сделано намеренно. Поведение управления историей команд задаётся в PSReadLine и специально фильтрует команды, содержащие секреты.
Далее объясню, где искать эти правила, какие шаблоны используются для очистки и как при необходимости изменить поведение.
Пример поведения — что наблюдалось
В одном из случаев выполнены команды, показанные ниже: при первой сессии был получен токен через Invoke-RestMethod и вычислен хэш:
- Процесс: This is process ID 14500.
- Команда получения токена: $token = (Invoke-RestMethod https://corpsite.com/odata/tokens -UseDefaultCredentials).value.token
- Проверка: $token.GetHashCode() вернула 717912038.
После закрытия PowerShell и открытия новой сессии процесс уже имел другой PID (This is process ID 5356). При просмотре файла истории последних 5 строк команда с получением токена отсутствовала. Видимое в истории сохранялось только безопасное взаимодействие, например $token.GetHashCode(), но не присвоение токена.
Где заданы правила очистки истории
Поведение определяется опцией AddToHistoryHandler в PSReadLine. Это обработчик (функция), который решает, попадёт ли конкретная команда в файл истории.
По умолчанию эта функция называется GetDefaultAddToHistoryOption и реализует ряд проверок на содержание потенциально секретной информации. Если команда совпадает с одним из критериев, она не сохраняется в файл истории (хранится только в оперативной памяти текущей сессии).
Какие проверки выполняются
Одно из ключевых правил — поиск совпадений по регулярному выражению:
password|asplaintext|token|apikey|secret
Если любая часть команды совпадает с этим regex (включая слово token), команда будет отфильтрована и не записана в файл истории. Именно поэтому команда с Invoke-RestMethod, содержащая слово token, не сохранилась.
Исключения и «безопасные» команды управления секретами
Существуют исключения — набор безопасных cmdlet, которые не считаются вредными и сохраняются в истории. В коде PSReadLine эти команды перечислены в s_SecretMgmtCommands, примерный список:
- Get-Secret
- Get-SecretInfo
- Get-SecretVault
- Register-SecretVault
- Remove-Secret
- Set-SecretInfo
- Set-SecretVaultDefault
- Test-SecretVault
- Unlock-SecretVault
- Unregister-SecretVault
- Get-AzAccessToken
Если команда совпадает с одной из этих безопасных строк, она может быть разрешена для записи в историю.
Примеры правил на практике
- $test="something" — будет сохранено в истории.
- $token = ‘something’ — не будет сохранено в файл истории.
- $token = Get-Location — будет сохранено.
- $token = $something — не будет сохранено.
Эти примеры демонстрируют, что наличие буквального слова token или других ключевых слов в командной строке влияет на решение обработчика.
Как изменить поведение (и предупреждение)
Можно переопределить AddToHistoryHandler в профиле PowerShell. Пример команды, которая отключит фильтрацию и будет добавлять всё в историю:
Set-PSReadLineOption -AddToHistoryHandler { return $true }
Однако такое поведение не рекомендуется по соображениям безопасности. Файл истории хранится в виде простого текста, и запись секретных значений (токенов, паролей, ключей) может нарушить безопасность ваших данных.
Выводы (кратко)
- Решение о том, какие команды сохранять, задаёт AddToHistoryHandler в PSReadLine (по умолчанию GetDefaultAddToHistoryOption).
- Фильтрация основана, в том числе, на regex password|asplaintext|token|apikey|secret.
- Есть список безопасных команд управления секретами (Get-Secret и т. п.), которые являются исключениями.
- Переопределить поведение можно, но это потенциально небезопасно, так как история — plaintext.