skysilver

<<< Назад

Сценарий контроля состояния SSL сертификатов сайтов

Небольшой скрипт в виде сценария (или метода) для контроля сроков действия SSL сертификата сайта с отправкой статуса в Telegram.

Возникла задача мониторить сроки действия SSL-сертификатов некоторых сайтов. Что особенно актуально при использовании сертификатов от бесплатных сервисов Let's Encrypt и ему подобных, которые выпускают сертификаты на короткий срок (3 месяца).

В основе лежит функция checkSSL ($domain, $port), которая в качестве обязательного параметра принимает доменное имя (DNS) конкретного сайта. Опционально можно указать порт, если используется не стандартный 443-ий. Функция возвращает ассоциативный массив со значениями:

  • status - текущее состояние сертификата сайта (1 - сертификат есть и выдан на проверяемый домен, 0 - сертификат отсутсвует или выдан на другой домен).
  • validTo - время истечения действия сертификата (в формате Y-m-d H:i:s).
  • validDays - срок действия сертификата в днях.

Пример использования функции checkSSL.

$report = checkSSL('connect.smartliving.ru');

echo 'Статус = ' . $report['status'] . '<br>';
echo 'Действителен до = ' . $report['validTo'] . '<br>';
echo 'Осталось дней = ' . $report['validDays'] . '<br>';

Полный код функции checkSSL выглядит следующим образом.

function checkSSL ($domain, $port = 443)
{
    $result = array('status' => false, 'validTo' => '', 'validDays' => '');

    $stream = stream_context_create(array('ssl' => array('capture_peer_cert' => true)));
    $socket = stream_socket_client("ssl://$domain:$port", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $stream);

    if ($socket) {
        $cont = stream_context_get_params($socket);
        $cert_ressource = $cont['options']['ssl']['peer_certificate'];
        $cert = openssl_x509_parse($cert_ressource);

        $namepart = explode('CN=', $cert['name']);

        if (count($namepart) == 2) {
            $cert_domain = trim($namepart[1], '*. ');
            $check_domain = substr($domain, -strlen($cert_domain));
            $result['status'] = ($cert_domain == $check_domain);
            $result['validTo'] = date('Y-m-d H:i:s', $cert['validTo_time_t']);
            $result['validDays'] = date_diff(new DateTime(), new DateTime($result['validTo']))->days;
        }
    }

    return $result;
}

Для удобства использования обернул все это дело в класс SSLChecker, в котором объекты - это сайты, которые требуется мониторить. В свойствах объектов указывается доменное имя сайта (domain) и хранятся текущие состояния его сертификата (status, validTo, validDays). Классовый метод checkSSL отвечает непосредственно за выполнение контроля с помощью функции checkSSL() и запись в свойства объекта актуальных данных.

class_sslchecker

Код классового метода checkSSL.

DebMes('Checking SSL status for ' . $this->getProperty('domain'));

$port = $this->getProperty('port');

$report = checkSSL($this->getProperty('domain'), ($port != '' && $port > 0) ? $port : 443);

$this->setProperty('status', ($report['status'] && $report['validDays'] > 0) ? 1 : 0);
$this->setProperty('validTo', $report['validTo']);
$this->setProperty('validDays', $report['validDays']);
$this->setProperty('lastCheck', date('Y-m-d H:i:s'));

function checkSSL ($domain, $port = 443)
{
    $result = array('status' => false, 'validTo' => '', 'validDays' => '');

    $stream = stream_context_create(array('ssl' => array('capture_peer_cert' => true)));
    $socket = stream_socket_client("ssl://$domain:$port", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $stream);

    if ($socket) {
        $cont = stream_context_get_params($socket);

        $cert_ressource = $cont['options']['ssl']['peer_certificate'];
        $cert = openssl_x509_parse($cert_ressource);

        $namepart = explode('CN=', $cert['name']);

        if (count($namepart) == 2) {
            $cert_domain = trim($namepart[1], '*. ');
            $check_domain = substr($domain, -strlen($cert_domain));
            $result['status'] = ($cert_domain == $check_domain);
            $result['validTo'] = date('Y-m-d H:i:s', $cert['validTo_time_t']);
            $result['validDays'] = date_diff(new DateTime(), new DateTime($result['validTo']))->days;
        }
    }

    return $result;
}

Далее любым удобным способом настраивается вызов методов checkSSL по расписанию. Я раз в сутки выполняю сценарий, который берет все объекты класса и последовательно (в фоне) запускает метод каждого объекта.

$sites = getObjectsByClass('SSLChecker');

foreach ($sites as $site) {
    callMethodSafe($site['TITLE'] . '.checkSSL');
}

Чтобы получать отчеты в Telegram использую такой сценарий.

$report = "<b>Состояние SSL-сертификатов</b> \n\n";

$sites = getObjectsByClass('SSLChecker');

foreach ($sites as $site) {
    $status = getGlobal($site['TITLE'] . '.status');    
    $domain = getGlobal($site['TITLE'] . '.domain');
    $days = getGlobal($site['TITLE'] . '.validDays');
    $validTo = getGlobal($site['TITLE'] . '.validTo');
    $lastCheck = getGlobal($site['TITLE'] . '.lastCheck');

    if ($status == 1) {
        $report .= "✅";
    } else {
        $report .= "‼️";
    }

    $report .= ' ' . $domain . ' (' . getNumberWord($days, array('день', 'дня', 'дней')) . ") \n";
    $report .= '      <code>' . $validTo . '</code>';
    $report .= "\n";
}

$report .= " \n Последняя проверка:<i> $lastCheck</i>";

include_once (DIR_MODULES . 'telegram/telegram.class.php');
$telegram_module = new telegram();
$telegram_module->sendMessageToAdmin($report);

Результат.

ssl_check_telegram

Обсуждение (4) (16)

Смотрите так же:
12.07.2019 MajorDoMo и Яндекс Алиса. Алиса, включи канал Карусель.
20.06.2019 MajorDoMo и Яндекс Алиса. Алиса, измени цвет бра на красный.
18.06.2019 MajorDoMo и Яндекс Алиса. Алиса, сделай ярче настольную лампу.
17.06.2019 MajorDoMo и Яндекс Алиса. Алиса, включи свет на кухне.
10.06.2019 MajorDoMo и Яндекс Алиса. Модуль Yandex Home.
06.06.2019 MajorDoMo и Яндекс Алиса. Объединение аккаунтов.
05.06.2019 MajorDoMo и Яндекс Алиса. Регистрация приватного навыка.
03.06.2019 Загрузка PHP-расширения PDO MySQL в Windows
01.06.2019 MajorDoMo и Яндекс Алиса. Публикация вебхуков.
29.05.2019 MajorDoMo и Яндекс Алиса. Общие сведения.
22.05.2019 Экспресс контроль состояния циклов в Linux
26.02.2019 Экспорт графиков в PNG-файл в модуле Charts
26.01.2019 Мультисерийный кастомный график в модуле Charts
30.12.2018 Личные итоги 2018 года
13.12.2018 График с цветовой индикацией выхода величины за пределы
12.11.2018 Кастомный график в модуле Charts
15.08.2018 Кронштейн NB F120 (North Bayou)
18.07.2018 WiFi-информер на светодиодных матрицах MAX7219 и ESP8266. Часть 3.
20.06.2018 WiFi-информер на светодиодных матрицах MAX7219 и ESP8266. Часть 2.
15.06.2018 WiFi-информер на светодиодных матрицах MAX7219 и ESP8266. Часть 1.
20.05.2018 Кросс-компиляция ядра для Banana Pi M2U
14.05.2018 Ссылки на ресурсы по MajorDoMo
02.03.2018 Знакомство и тестирование Banana Pi M2U
21.02.2018 Распаковка Banana Pi M2U
14.02.2018 Одноплатный ПК для MajorDoMo
14.08.2018 Заметки по железу
23.01.2018 Мой взгляд на вопрос голосового управления в MajorDoMo
17.01.2018 Обзор цен на устройства Xiaomi
24.12.2017 Гирлянда на ESP8266 и WS2812
20.12.2017 Блог им. skysilver

Киров, Россия

На форуме: skysilver

Веб-сайт:
http://connect.smartliving.ru/profile/461