ERR_BAD_SSL_CLIENT_AUTH_CERT означает, что сайт попросил у браузера сертификат пользователя и прервал защищённое соединение: сертификат не подошёл, оказался просроченным или браузер не прислал никакого. Такая ошибка встречается там, где вход выполняется не паролем, а сертификатом: банк-клиент, корпоративные порталы, отраслевые и государственные системы.
Мы собрали стенд из Chromium 149, nginx 1.22 и своего сервера на Python, выпустили свой центр сертификации и три сертификата пользователя — правильный, выданный чужим центром и просроченный — и проверили, какой из них браузер отправляет, что отвечает сервер и что видит человек.
Что означает ERR_BAD_SSL_CLIENT_AUTH_CERT
В файле net_error_list.h у кода −117 описание:
The SSL handshake failed because of a bad or missing client certificate.
Перевод: установка защищённого соединения не удалась из-за неподходящего или отсутствующего сертификата клиента.
Обычно при HTTPS проверяет только браузер: подлинный ли сертификат у сайта. Но сервер может потребовать и встречную проверку — чтобы пользователь подтвердил, кто он. Для этого у пользователя должен быть свой сертификат с закрытым ключом: в хранилище системы, в браузере или на токене. Такой вход называют взаимной аутентификацией, или mTLS.
Если сертификат не прошёл проверку, сервер отправляет сигнал TLS об ошибке, и браузер показывает ERR_BAD_SSL_CLIENT_AUTH_CERT.
Как выглядит ошибка
На экране Chrome и Яндекс Браузера:
Доступ к site.test запрещен
Ваш сертификат отклонен сайтом site.test или не был выдан.
Обратитесь за помощью к системному администратору.
ERR_BAD_SSL_CLIENT_AUTH_CERT
Сам текст подсказывает главное: ошибка про ваш сертификат, а не про сертификат сайта. Подсказка про администратора не случайна: такие сертификаты обычно выдаёт организация, банк или удостоверяющий центр, и исправить их можно только там.
Какие ответы сервера дают эту ошибку
В openssl_ssl_util.cc сигналы TLS переводятся в коды Chromium. В ERR_BAD_SSL_CLIENT_AUTH_CERT превращаются восемь сигналов:
| Сигнал TLS | Что он означает |
|---|---|
| bad_certificate (42) | сертификат испорчен или подпись неверна |
| unsupported_certificate (43) | тип сертификата не поддерживается |
| certificate_revoked (44) | сертификат отозван |
| certificate_expired (45) | срок сертификата истёк |
| certificate_unknown (46) | другая проблема с сертификатом |
| unknown_ca (48) | сертификат выдан неизвестным центром |
| access_denied (49) | сертификат верный, но доступа нет |
| certificate_required (116) | сертификат нужен, а его не прислали |
Есть ещё две поправки в ssl_client_socket_impl.cc. Первая: в TLS нет сигнала «сертификат не прислан» для старых версий протокола, и сервер отвечает общим handshake_failure. Браузер ловит этот случай: если сервер просил сертификат, а браузер его не отправил, общий сбой тоже становится ERR_BAD_SSL_CLIENT_AUTH_CERT. Вторая: access_denied без запроса сертификата считается ошибкой протокола — по комментарию в коде, так отвечают некоторые сетевые фильтры, когда блокируют страницу.
Стенд: что делает браузер с разными сертификатами
Сертификаты мы положили в хранилище браузера, а выбор настроили политикой AutoSelectCertificateForUrls, чтобы он подставлялся без окна выбора. Серверы требовали сертификат, выданный нашим центром.
| Сертификат в браузере | Сервер на Python, TLS 1.2 | Сервер на Python, TLS 1.3 | nginx, ssl_verify_client on |
|---|---|---|---|
| правильный | 200, сертификат принят | 200 | 200 |
| нет сертификата | ERR_BAD_SSL_CLIENT_AUTH_CERT | эта ошибка в 2 из 5 попыток, в 3 — ERR_SOCKET_NOT_CONNECTED | страница 400 «No required SSL certificate was sent» |
| выдан чужим центром | ERR_BAD_SSL_CLIENT_AUTH_CERT | ERR_BAD_SSL_CLIENT_AUTH_CERT | страница 400 «No required SSL certificate was sent» |
| просроченный | ERR_BAD_SSL_CLIENT_AUTH_CERT | ERR_BAD_SSL_CLIENT_AUTH_CERT | страница 400 «No required SSL certificate was sent» |
Все ответы приходили за 0,05–0,3 секунды. Из таблицы видны три вещи.
Просроченный сертификат браузер не отправляет вообще. В журнале сервера на Python для него записано «peer did not return a certificate» — клиент не вернул сертификат. В client_cert_matcher.cc это правило записано прямо: «Only offer unexpired certificates» — предлагать только непросроченные сертификаты.
Сертификат чужого центра браузер не предлагает nginx. nginx сообщает в запросе сертификата список допустимых центров — тех, что указаны в ssl_client_certificate. Chromium выбирает только сертификаты от этих центров. Наш сервер на Python такого списка не передавал, поэтому получил чужой сертификат и отказал с ошибкой «unable to get local issuer certificate».
nginx отвечает страницей, а не ошибкой соединения. При
ssl_verify_client on nginx завершает рукопожатие и возвращает HTTP 400
с текстом «No required SSL certificate was sent», а в журнал пишет
«client sent no required SSL certificate». Посетитель видит не
ERR_BAD_SSL_CLIENT_AUTH_CERT, а короткую страницу nginx. С
ssl_verify_client optional страница открылась без сертификата, а
переменная $ssl_client_verify была NONE.
В TLS 1.3 результат без сертификата плавал: сервер проверяет сертификат уже после того, как браузер считает соединение установленным, и сигнал об ошибке иногда приходит, когда браузер уже отправил запрос.
Ошибка без запроса сертификата
Мы проверили и обратный случай: сервер сертификат не просит, но сразу отвечает одним из сигналов TLS.
| Сигнал сервера | Что показал Chromium 149 |
|---|---|
| bad_certificate (42) | ERR_BAD_SSL_CLIENT_AUTH_CERT |
| certificate_expired (45) | ERR_BAD_SSL_CLIENT_AUTH_CERT |
| certificate_unknown (46) | ERR_BAD_SSL_CLIENT_AUTH_CERT |
| unknown_ca (48) | ERR_BAD_SSL_CLIENT_AUTH_CERT |
| certificate_required (116) | ERR_BAD_SSL_CLIENT_AUTH_CERT |
| access_denied (49) | ERR_SSL_PROTOCOL_ERROR |
| handshake_failure (40) | ERR_SSL_VERSION_OR_CIPHER_MISMATCH |
Значит, ERR_BAD_SSL_CLIENT_AUTH_CERT может появиться и на сайте, где никаких сертификатов пользователя нет. Так бывает, когда между вами и сайтом стоит программа, которая сама разбирает защищённые соединения, — антивирус с проверкой HTTPS, корпоративный фильтр, неисправный прокси, — и отвечает неправильным сигналом.
Почему возникает ошибка
По стенду и исходному коду причины такие:
- Сертификат не установлен. Сайт требует сертификат, а в хранилище его нет — например, на новом компьютере или в другом браузере.
- Сертификат просрочен. Браузер его даже не предложит.
- Неверные дата и время на компьютере. Браузер сравнивает срок сертификата с часами компьютера. Если часы ушли вперёд или назад, действующий сертификат кажется просроченным. Разработчики Chromium прямо отмечают это в комментарии к проверке срока.
- Сертификат выдан не тем центром. Например, у вас сертификат для другой системы или старого контура.
- Сертификат отозван. Организация отозвала его, например после увольнения или замены токена.
- Не выбран нужный сертификат. Если сертификатов несколько, браузер мог запомнить неправильный выбор для этого сайта.
- Нет доступа к закрытому ключу. Токен не вставлен, драйвер не установлен или программа криптозащиты не работает.
- Программа в середине соединения. Антивирус с проверкой HTTPS, VPN или корпоративный прокси вмешиваются в рукопожатие.
- Ошибка настройки сервера. Сервер проверяет сертификаты не по тому центру или с неполной цепочкой.
Как исправить ERR_BAD_SSL_CLIENT_AUTH_CERT: пользователю
1. Проверьте дату и время
В Windows: «Параметры» → «Время и язык» → «Дата и время», включите «Установить время автоматически» и нажмите «Синхронизировать». Проверьте часовой пояс. После исправления перезапустите браузер.
2. Перезапустите браузер, чтобы выбрать сертификат заново
Chrome запоминает выбранный для сайта сертификат до конца сеанса. Закройте все окна браузера — не только вкладку — и откройте сайт снова. Браузер покажет окно «Выберите сертификат». Выберите тот, что выдан для этой системы, и нажмите «ОК».
3. Проверьте, что сертификат установлен и действует
В Chrome: «Настройки» → «Конфиденциальность и безопасность» →
«Безопасность» → «Настроить сертификаты». В Windows можно открыть
хранилище напрямую: нажмите Win+R, введите certmgr.msc и откройте
«Личное» → «Сертификаты». Найдите свой сертификат и посмотрите поле «Срок
действия». Сертификат должен быть с закрытым ключом: в свойствах будет
надпись «Есть закрытый ключ для этого сертификата».
Если сертификата нет или срок истёк, получите новый там, где его выдали: в банке, удостоверяющем центре или у администратора.
4. Вставьте токен и проверьте программу криптозащиты
Если ключ хранится на токене — Рутокен, JaCarta, ESMART, — вставьте его до открытия сайта и проверьте, что драйвер установлен. Если сайт работает через КриптоПро CSP, проверьте, что программа установлена и лицензия действует.
5. Отключите проверку HTTPS в антивирусе и VPN
Антивирус с проверкой защищённых соединений подменяет соединение своим, и сертификат пользователя до сайта не доходит. Временно отключите эту функцию или добавьте сайт в исключения. Отключите VPN и прокси и повторите вход.
6. Очистите кэш и cookie сайта
В Chrome: нажмите значок слева от адреса → «Настройки сайтов» → «Удалить данные». Ошибка рукопожатия случается до cookie, поэтому помогает это редко, но исключает старую сессию сайта.
Если нужно удалить данные полностью, нажмите Ctrl+Shift+Delete. В окне выберите диапазон «Всё время», отметьте «История браузера», «Файлы cookie и другие данные сайтов» и «Изображения и другие файлы, сохранённые в кеше» и нажмите «Удалить данные». Пароли при этом не удаляются, если не отметить их отдельно.
7. Очистите SSL-кэш Windows
Windows хранит состояние защищённых соединений отдельно от браузера.
Нажмите Win+R, введите inetcpl.cpl и нажмите Enter. В окне «Свойства:
Интернет» перейдите на вкладку «Содержание» и нажмите «Очистить
SSL». Затем перезапустите браузер.
8. Отключите расширения
Проверьте сайт в режиме инкогнито: расширения там по умолчанию выключены. Если сайт открылся, включайте расширения по одному.
9. Отключите QUIC
Многие инструкции советуют отключить экспериментальный протокол QUIC.
Введите в адресную строку chrome://flags, найдите через поиск
«Experimental QUIC protocol», выставьте значение «Disabled» и
перезапустите браузер. Мы не проверяли, помогает ли это при ошибке
сертификата клиента, но вреда нет: сайты продолжают работать по
обычному протоколу. После проверки верните значение «Default».
10. Проверьте брандмауэр и сбросьте сеть
Сторонний брандмауэр может разбирать защищённый трафик так же, как антивирус. Временно отключите его. Если не помогло, выполните сброс сетевых настроек: «Параметры» → «Сеть и Интернет» → «Дополнительные сетевые параметры» → «Сброс сети». Компьютер перезагрузится, сетевые адаптеры будут установлены заново.
11. Попробуйте другой браузер
Некоторые системы работают только в определённых браузерах. Например, сайтам с шифрованием по ГОСТу нужен браузер с поддержкой КриптоПро CSP.
12. Обновите браузер и операционную систему
Старые версии браузера и Windows могут не поддерживать алгоритмы,
которые требует сервер. Откройте chrome://settings/help и установите
последнюю версию, затем проверьте обновления Windows.
Если сайт с шифрованием по ГОСТу
Справка Яндекс Браузера пишет: «Яндекс Браузер поддерживает утилиту КриптоПро CSP в качестве СКЗИ» — то есть средства криптографической защиты. Там же приведены примеры сайтов, которые запрашивают шифрование TLS по ГОСТу: www.gosuslugi.ru, сайты на доменах .gov.ru, .kamgov.ru и .nalog.ru.
Чтобы такие сайты открывались:
- Установите КриптоПро CSP и КриптоПро ЭЦП Browser plug-in.
- В Яндекс Браузере: «Настройки» → «Системные», в разделе «Сеть» должна быть включена опция «Подключаться к сайтам, использующим шифрование по ГОСТ. Требуется КриптоПро CSP». По справке она включена по умолчанию.
- Если сайт требует электронную подпись на носителе, вставьте токен.
Как исправить ERR_BAD_SSL_CLIENT_AUTH_CERT: владельцу сайта
-
Проверьте, какие центры принимает сервер. В nginx это ssl_client_certificate: браузер предложит только сертификаты от центров из этого файла. Если пользователи получили сертификаты от нового центра, добавьте его.
-
Проверьте цепочку. Если сертификаты выдаёт промежуточный центр, серверу нужен и он, и корневой. В nginx глубину проверки задаёт ssl_verify_depth.
-
Решите, где отказывать. При
ssl_verify_client onnginx сам отвечает 400. Приoptionalможно проверять $ssl_client_verify в приложении и показывать понятную страницу: что за сертификат нужен и где его получить. -
Проверьте отзыв. Если сервер проверяет список отозванных сертификатов (ssl_crl), устаревший список отклонит и годные сертификаты.
-
Проверьте вручную. Запрос с сертификатом через curl покажет ответ сервера:
curl -v --cert user.pem --key user.key https://адрес-сайта/Если с этим сертификатом curl получает страницу, а браузер нет, причина на стороне пользователя.
-
Обновите серверное программное обеспечение, если клиенты используют новые типы ключей, которые старая версия не понимает.
Как выпустить тестовый сертификат клиента
Если вы являетесь разработчиком и настраиваете вход по сертификату, проверьте весь процесс на тестовом центре — именно так мы собирали стенд. Создайте свой центр сертификации командой OpenSSL:
openssl req -x509 -newkey rsa:2048 -nodes -keyout ca.key \
-subj "/CN=Test Client CA" -days 30 -out ca.pem
Затем ключ и сертификат пользователя с назначением clientAuth:
openssl req -new -newkey rsa:2048 -nodes -keyout user.key \
-subj "/CN=user" -out user.csr
printf "extendedKeyUsage=clientAuth\n" > user.ext
openssl x509 -req -in user.csr -CA ca.pem -CAkey ca.key \
-CAcreateserial -days 30 -extfile user.ext -out user.pem
Браузеры и Windows импортируют сертификат с ключом в формате PKCS#12, поэтому конвертируйте его в файл .p12:
openssl pkcs12 -export -in user.pem -inkey user.key -out user.p12
Файл ca.pem укажите серверу в ssl_client_certificate, а user.p12 загрузите в хранилище: в Windows — двойным щелчком по файлу, в Chrome — через «Настроить сертификаты» → «Импорт». После этого откройте сайт: если всё сделано правильно, браузер покажет окно выбора сертификата.
Что делать в организации
Если ошибка появляется на рабочем портале у многих сотрудников сразу, скорее всего, истёк срок сертификатов или центр сменили. Сообщите администратору адрес сайта, код ошибки и время. Если у одного сотрудника — проверьте его компьютер по шагам выше: дату, установленный сертификат, токен.
Источники
- Chromium, net/base/net_error_list.h — BAD_SSL_CLIENT_AUTH_CERT −117
- Chromium, net/ssl/openssl_ssl_util.cc — перевод сигналов TLS в коды ошибок
- Chromium, net/socket/ssl_client_socket_impl.cc — handshake_failure без сертификата и access_denied без запроса
- Chromium, net/ssl/client_cert_matcher.cc — отбор сертификатов по сроку и центру
- nginx: модуль ngx_http_ssl_module, директивы ssl_verify_client и ssl_client_certificate — nginx.org
- Яндекс Браузер: справка «Электронная подпись и шифрование по ГОСТу» — browser.yandex.ru
Похожие ошибки
| Ошибка | Что случилось |
|---|---|
| ERR_BAD_SSL_CLIENT_AUTH_CERT | сайт не принял сертификат пользователя |
| ERR_SSL_PROTOCOL_ERROR | сбой рукопожатия TLS без уточнения |
| ERR_SSL_VERSION_OR_CIPHER_MISMATCH | браузер и сервер не договорились о шифровании |
| ERR_SSL_UNRECOGNIZED_NAME_ALERT | сервер не узнал имя сайта |
Границы замера
Стенд — Chromium 149 под Linux, 18.10.2026, хранилище сертификатов NSS, выбор сертификата задан политикой. Окно выбора сертификата мы не проверяли: без политики браузер ждал выбора, и запрос висел до таймаута теста. Токены, КриптоПро CSP и хранилище Windows не проверялись — шаги для них взяты из справки. Сигналы TLS сервер отправлял нарочно: так, как ведут себя реальные фильтры, мы не проверяли.
Коротко
ERR_BAD_SSL_CLIENT_AUTH_CERT значит, что сайт потребовал сертификат пользователя и не получил подходящего. Проверьте дату и время, перезапустите браузер и выберите сертификат заново, убедитесь, что он установлен и не просрочен, вставьте токен. Браузер не отправляет просроченные сертификаты и сертификаты не тех центров, поэтому новый сертификат придётся получить там, где выдали старый. Если ошибка на обычном сайте, проверьте антивирус и VPN.
