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


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


Отчеты и Excel на страже памяти


В статье «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 {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() }}

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


  • Не заблокированные ? 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()

Теперь, сравнивая эти три переменные со значением $user.PasswordExpiry, мы сможем посылать соответствующие уведомления. Напомню, что отправка 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' {  }
}
}
}

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



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


на 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 у вас не развернута ? например, в случае отдельного терминального сервера, ? то решение тоже существует, пусть и чуть более сложное.


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


#Имя компьютера.
$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
    {
      "Все в порядке"
    }
  }
}

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


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


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


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


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

Комментарии (13)


  1. GDragon
    08.05.2018 13:52
    +3

    Пароли? Авторизация в домене по электронному пропуску + 6ти значный пин :)
    Из отличных бонусов — что бы выйти из кабинета тоже нужен пропуск а если убрать его со считывателя, комп блокируется автоматом.
    Никаких забывашек которые оставляют разблокированный пк.


    1. dimskiy
      09.05.2018 14:49

      Всегда хотел поработать в таком месте, из любопытства. Но не довелось ) ни админом, ни простым смертным не встречал таких инфраструктур


      1. GDragon
        09.05.2018 14:53

        Банк средних размеров :)
        Что забавно — инициатива исходила от ИТ и была вполне себе поддержана ОИБ и СБ.
        (Вход\выход из кабинета по карточкам уже был, мы ради снятия с себя пачки проблем вроде описанной в посте (а ещё люлей сотрудникам от ОИБ за записки с паролями и прочее) и придумали решение. Пин меняется, но пользователи его запоминают куда проще и быстрее чем пароль.)


  1. Angeld
    08.05.2018 17:52
    +1

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


    1. McARIS74
      09.05.2018 11:52

      Именно так и есть в нашей *****. Я в ней работаю не в управленцах. Моя работа относится к ******. Но тупизм простых паролей на рабочих пк и наклейки на мониторах, просто убивает. Добавьте сюда отключенный фаервол, имеющий место, сетевые расшаренные диски, с Центральным Офисом, картинки с 8 марта, с сайтов аля «васяпупкинточкаком, прямо в телах писем корпоративной почты. У меня просто волосы дыбом. А Айтишникам он мягко говоря… И причём, заметьте это очень крупная международная. О какой идёт речь не скажу, по причинам сохранения своей шкурыв целостности, просто знай Хабр. Это имеет место быть.


    1. dimskiy
      09.05.2018 14:52

      Полностью согласен. Ну или срок действия должен быть хотя бы полгода…


  1. jakshi
    09.05.2018 10:26

    Проще не устанавливать срок действия пароля, так безопасней и мороки меньше.


  1. sotnikdv
    09.05.2018 12:10
    +1

    Лучи добра людям, которые придумали менять пароль каждые 3 месяца. Теперь там стоит не нормальный пароль, который подобрать нереально, как на всех моих личных устройствах, а словарное слово и месяц-год последней смены.

    И так у всей огромной компании, слово и счетчик.

    Но по отчетам все мегасекурно и в соответствии с лучшими рекомендациями, чего уж там. А, ну и конечно, как говорит автор, модно-молодежно, это важнее всего.


  1. alar0n
    11.05.2018 08:12

    Строка запуска explorer shell:::{2559a1f2-21d7-11d4-bdaf-00c04f60b9f0}

    Кто нибудь знает как на 10-ке/2016 её вызвать?


    1. avelor
      11.05.2018 08:58

      Так же как и в прочих системах. Создать ярлык например. Или пуск-выполнить. Или любым другим образом…


      1. alar0n
        11.05.2018 09:30

        Сами то пробовали? Проверил на 4-х десятках и на 2016. Ничего не происходит при вводе команды.


        1. avelor
          11.05.2018 11:29

          да, попробовал. сейчас попробовал на рабочей 10ке — да, не работает.
          на двух дома — работает…


          1. alar0n
            11.05.2018 12:44

            Вот на рабочих у меня тоже не работает.
            Дома пока не тестил :)