Хабрахабр

Влияние маленького окошка на память пользователя, и что с этим делать

И это вместо окна прямо по центру, как было раньше! Еще с выходом в свет Windows Vista\2008 администраторы столкнулись с маленькой, но неприятной проблемой: оповещение об истечении срока действия пароля стало сиротливо появляться в самом неприметном углу экрана.

Конечно, не проблема года, но явление назойливое и неприятное. Отсюда и смена паролей в последний момент, под аккомпанемент отказов доступа; и негодование, почему вдруг перестал работать VPN, и что с этим делать в командировке. Поэтому разбираемся, как его одолеть.

Благодаря этому механизму всегда можно получить отчет о сроках действия пользовательских паролей. В статье «Excel вместо PowerShell: запросы к AD и системные отчеты» я рассказывал, как вытащить информацию из Active Directory при помощи Excel. В современных доменах для этого существует атрибут msDS-UserPasswordExpiryTimeComputed, который находится в классе user.

При помощи Power Query мы можем легко получить подобную табличку:


Отчет о сроках действия пароля в MS Excel.

Теперь, если добавить формулу вида

=ЕСЛИ([@[msDS-UserPasswordExpiryTimeComputed]]<ТДАТА();"Пароль просрочен!";ЕСЛИ([@[msDS-UserPasswordExpiryTimeComputed]]-5<ТДАТА();"Пароль скоро закончится!";"ОК"))

в соседний столбец, то мы получим таблицу уже такого вида:


Делаем отчет более наглядным.

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


И еще более наглядным.

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

Попробуем использовать в качестве аккаунт-менеджера PowerShell.

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

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

$users = Get-ADUser -filter ` -Properties "Name", "EmailAddress", "msDS-UserPasswordExpiryTimeComputed" | ` Select-Object -Property "Name", "EmailAddress", ` @{Name = "PasswordExpiry"; Expression = {[datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed").tolongdatestring() }}

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

  • Не заблокированные ― Enabled -eq $True.
  • Те, у кого пароль имеет срок жизни ― PasswordNeverExpires -eq $False.
  • Те, у кого вообще не установлен пароль ― PasswordLastSet -gt 0.

Для удобства задаем три варианта времени предупреждения ― за 7, за 3 и за 1 день: В результате мы получим таблицу значения с именем пользователя, его адресом и датой истечения пароля.

$SevenDayWarnDate = (get-date).adddays(7).ToLongDateString()
$ThreeDayWarnDate = (get-date).adddays(3).ToLongDateString()
$OneDayWarnDate = (get-date).adddays(1).ToLongDateString()

PasswordExpiry, мы сможем посылать соответствующие уведомления. Теперь, сравнивая эти три переменные со значением $user. Напомню, что отправка e-mail производится при помощи командлета Send-MailMessage.

Но не обязательно уведомлять пользователей исключительно по почте ― можно использовать материал «Еще не бот, но уже что-то ― получаем уведомления от Zabbix в мессенджеры» и отсылать уведомления по любому другому каналу связи.

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

Ознакомиться

Import-Module ActiveDirectory #Создаем пороги срабатывания уведомлений
$SevenDayWarnDate = (get-date).adddays(7).ToLongDateString()
$ThreeDayWarnDate = (get-date).adddays(3).ToLongDateString()
$OneDayWarnDate = (get-date).adddays(1).ToLongDateString() #Настройка текста сообщений
$MailSender = " Бот-Напоминалка <bot@domain.com>"
$Subject = 'Внимание! Срок действия Вашего пароля заканчивается'
$EmailStub1 = 'Я бот-напоминалка. Ваш пароль закончится'
$EmailStub2 = 'через'
$EmailStub3 = 'дней'
$EmailStub4 = '. Пожалуйста, заблаговременно измените свой пароль. Обратитесь в службу технической поддержки, если вы испытываете трудности со сменой пароля.'
$SMTPServer = 'smtp.domain.com' #Получаем пользователей
$users = Get-ADUser -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False -and PasswordLastSet -gt 0 } ` -Properties "Name", "EmailAddress", "msDS-UserPasswordExpiryTimeComputed" | Select-Object -Property "Name", "EmailAddress", ` @{Name = "PasswordExpiry"; Expression = {[datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed").tolongdatestring() }} #Проверяем сроки действия и отправляем уведомления.
foreach ($user in $users) { if ($user.PasswordExpiry -eq $SevenDayWarnDate) { $days = 7 $EmailBody = $EmailStub1, $user.name, $EmailStub2, $days, $EmailStub3, $SevenDayWarnDate, $EmailStub4 -join ' ' Send-MailMessage -To $user.EmailAddress -From $MailSender -SmtpServer $SMTPServer -Subject $Subject -Body $EmailBody } elseif ($user.PasswordExpiry -eq $ThreeDayWarnDate) { $days = 3 $EmailBody = $EmailStub1, $user.name, $EmailStub2, $days, $EmailStub3, $ThreeDayWarnDate, $EmailStub4 -join ' ' Send-MailMessage -To $user.EmailAddress -From $MailSender -SmtpServer $SMTPServer -Subject $Subject ` -Body $EmailBody } elseif ($user.PasswordExpiry -eq $oneDayWarnDate) { $days = 1 $EmailBody = $EmailStub1, $user.name, $EmailStub2, $days, $EmailStub3, $OneDayWarnDate, $EmailStub4 -join ' ' Send-MailMessage -To $user.EmailAddress -From $MailSender -SmtpServer $SMTPServer -Subject $Subject -Body $EmailBody } else {} }

Рассмотрим еще один вариант уведомления. Теперь пользователи предупреждены, и остается надеяться на их ответственность.

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

Приведу пример простого скрипта на PowerShell, подсунутого в автозагрузку групповыми политиками:

$user= Get-ADUser -Identity $env:username -Properties 'msDS-UserPasswordExpiryTimeComputed','PasswordNeverExpires'
if ( -not $user.'PasswordNeverExpires') {
$diff=(new-timespan -start (get-date) -end ([datetime]::FromFileTime($user."msDS-UserPasswordExpiryTimeComputed"))).Days if ($diff -lt 7) {
$msgBoxInput = [System.Windows.MessageBox]::Show("Ваш пароль истекает через "+ $diff + " дней!`nПерейти к диалогу смены пароля?","Внимание!","YesNo","Warning") switch ($msgBoxInput) { 'Yes' { cmd /c "explorer shell:::{2559a1f2-21d7-11d4-bdaf-00c04f60b9f0}" } 'No' { }
}
}
}

После выхода Windows 2012 он исчез из меню «Пуск» и стал доступен только при нажатии Ctrl+Alt+Del или Ctrl+Alt+End в случае подключения по RDP. Строка запуска explorer shell:::{2559a1f2-21d7-11d4-bdaf-00c04f60b9f0} ― это запуск интерфейса «Безопасность Windows».

Окно уведомления.
Для ценителей под спойлером старая версия скрипта.

на AutoIT

#Include <AD.au3>
#include <Date.au3> _AD_Open()
$array=_AD_GetPasswordInfo() if $array[9] <> "" then $t=_DateDiff ( "d", _NowCalc(), $array[9] ) if $t < 7 Then
$a=MsgBox ( 4, "Внимание!", "Срок действия вашего пароля истекает через " &$t &" дней."&@crlf&"Перейти к диалогу смены пароля?" )
if $a=6 then Run("explorer shell:::{2559a1f2-21d7-11d4-bdaf-00c04f60b9f0}")
sleep(1000)
endif
endif
endif
_AD_Close()

Она выдает массив значений с информацией о пароле, в том числе и временем его истечения. Простой реализации помогает функция _AD_GetPasswordInfo() из библиотеки AD.au3.

После внедрения этого механизма какие-либо проблемы с просроченными паролями перестали появляться.

Если инфраструктура Active Directory у вас не развернута ― например, в случае отдельного терминального сервера, ― то решение тоже существует, пусть и чуть более сложное.

Вернемся к примерам на PowerShell: Для этого нам понадобится чуть-чуть магии WMI и любимый скриптовый язык.

#Имя компьютера.
$Computer = $env:computername
#Имя пользователя
$UserName = $env:username
#Дельта в днях
$Days = 2
$User = [ADSI]"WinNT://$Computer/$UserName,user"
$Flags = $User.UserFlags.psbase.Value #Проверка существования срока жизни пароля.
If ($Flags -band 65536)
{ "Пароль никогда не имеет срока действия"
} Else
{ #Конвертируем время в дни. $AgeDays = $User.PasswordAge.psbase.Value / 86400 $MaxAge = $User.MaxPasswordAge.psbase.Value / 86400 If ($AgeDays -gt $MaxAge) { "Пароль просрочен" } Else { If (($AgeDays + $Days) -gt $MaxAge) { "Пароль будет просрочен через $Days дней" } Else { "Все в порядке" } }
}

При должной доработке такой скрипт может уведомлять пользователей при регулярном запуске или при входе в систему.

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

Обязательным остается только требование к длине паролей (вспоминая известную картинку от xkcd). Поэтому все больше мне близка практика, когда пользователи сами придумывают пароли, но при этом регулярно проводится аудит их творчества путем атаки по словарю утилитами вроде L0phtCrack.

Ну, а что ― система не ругается, а ИБ эта ваша… понапридумывали тут. Так можно и людям жизнь облегчить, и избежать защитной реакции на «закручивание гаек» в виде чудесных сочетаний вроде Qwerty123.

Кстати, а у вас есть аккаунт-менеджер или какая-нибудь модно-молодежная практика смены паролей?

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть