Перед сменой работы, запуском сайта или привычкой «просто дописать восклицательный знак» к старому паролю многие сначала ищут: не всплывала ли уже эта строка в слитых базах. В выдаче рядом стоят «проверка сложности пароля», Have I Been Pwned и «онлайн-поиск по утечкам» — заголовки звучат как один и тот же ответ. Откройте страницы: протоколы расходятся. Одни отправляют содержимое поля POST-ом на свой хост, другие просят у третьей стороны список суффиксов хеша, третьи скачивают открытый словарь слабых паролей и сравнивают его во вкладке. На вопрос «ушёл ли пароль с этой страницы» получаются три разных ответа.

Здесь нет разбора шкалы «слабый / средний / сильный» и нет инструкции, как бить чужие базы. Вопрос уже: что доказывает локальная сверка с открытым списком и что доказывает поиск по большой сетевой базе, если его честно реализовали. Проверка пароля в MyPassGen относится к первому типу: кандидат на сервер не уходит; страница сверяет открытый список слабых паролей, который подгружается вместе с сайтом; все инструменты открываются без учётной записи. Дальше — граница и способ проверить её во вкладке «Сеть» инструментов разработчика.

Три разные «проверки пароля»

Сначала назовите протоколы своими именами. В рекламном тексте легко поставить рядом «локально», «ничего не уходит» и «проверили по утечкам» — и при этом иметь в виду три разные схемы.

Способ Что покидает браузер На какой вопрос отвечает
Отдать пароль сайту Открытый текст или обратимое поле формы Чужой сервер говорит «проверили» — доказательств вы не видите
Диапазонный запрос с k-анонимностью (HIBP) Первые 5 шестнадцатеричных символов SHA-1 или NTLM Есть ли этот хеш в корпусе, который они ведут
Локальная сверка с открытым списком слабых паролей Статический файл словаря, не ваш ввод Не из тех ли это строк, что годами берут первыми: 123456, password

Первый способ проще всего нажать и труднее всего проверить. Страница может обещать «сразу удалить запрос». Журналы, резервные копии и скрипты аналитики всё равно способны оставить копию. Второй — схема, которую Have I Been Pwned описывает для Pwned Passwords: браузер сначала считает хеш, на api.pwnedpasswords.com/range/{prefix} уходит только префикс, суффиксы сравнивают уже на устройстве. Третий не отправляет даже префикс. Словарь — открытый набор частых слабых паролей, обычно от нескольких сотен до десяти тысяч строк, а не «каждый слив в интернете».

Национальный институт стандартов и технологий США в NIST SP 800-63B-4 просит проверяющую сторону сверять новый или сменённый пароль со списком «часто используемых, ожидаемых или уже скомпрометированных» значений и не наслаивать сверху обязательные правила «заглавная + цифра + спецсимвол». Там же сказано: чёрный список нужен, чтобы отсечь догадки, которые онлайн-атакующий пробует первыми; когда список уже шире окна ограничения частоты, лишние строки почти ничего не дают. Именно здесь стоит локальный топ-список: первое сито для обычных слабых паролей, а не поиск по всем файлам утечек.

Сначала вопрос, потом инструмент

«Словарь попробует это первым?» и «эта строка была в конкретном сливе?» — разные предложения. Локальный список отвечает на первое. Диапазонный запрос по большому корпусу отвечает на второе только для той базы, которой располагает другая сторона. Ни то ни другое не отменяет правило: один пароль нельзя таскать по всем сайтам.

Что значит отдать открытый текст сайту

Часть «онлайн-проверок пароля» до сих пор кладёт строку из поля прямо в тело запроса. Одни называют JSON-поле password. Другие бросают её в строку запроса. Третьи накладывают обратимое кодирование и шлют POST. Для браузера это тот же класс трафика, что и форма входа: удалённый хост, обратный прокси и журнал доступа видят эту отправку.

HTTPS закрывает только подслушивание на пути. Он не мешает дальней стороне писать открытый текст на диск и не мешает скрипту аналитики переслать поле дальше. Вы сокращаете другое: появился ли у этой одной проверки ещё один участник, который теперь знает строку. Это не обязанность HTTPS. В предыдущей заметке как на месте проверить, что шифрование в браузере не отправило открытый текст то же правило: слоган не доказывает, трафик — доказывает.

Есть и тихий способ отдать строку: вписать кандидата в параметр адреса, а ссылку переслать коллеге или бросить в тикет. Query попадает в строку запроса и в журнал на той стороне. Часть сторонних ресурсов всё ещё получает путь и query в Referer. Если это живой пароль от аккаунта, вы сами его размазываете. Безопасное значение по умолчанию: настоящий пароль остаётся в поле текущей вкладки. Не пишите его в URL и не вставляйте в «проверку», которая уносит оригинал.

Поиск по большой базе, который шлёт только префикс

Диапазонный API Have I Been Pwned отделяет «поискать в большом корпусе» от «отдать оригинал». По документации: закодировать пароль в UTF-8, посчитать SHA-1 (есть и NTLM), взять первые пять шестнадцатеричных символов и запросить GET https://api.pwnedpasswords.com/range/{prefix}. В ответе — суффиксы и число вхождений через двоеточие. Клиент на устройстве склеивает префикс с суффиксом и ищет полное совпадение. Troy Hunt называет это k-анонимностью в Understanding Have I Been Pwned's Use of SHA-1 and k-Anonymity: сервер видит корзину хешей, не полный хеш и не пароль.

Когда Cloudflare публиковал схему вместе с HIBP, в тексте были цифры, которые до сих пор можно сверить: при префиксе из 5 символов в корзине по медиане около 305 хешей, медианный ответ — около 12,2 КБ. API ещё даёт Add-Padding: true: каждый ответ дополняют примерно до 800–1000 строк, чтобы по длине ответа нельзя было угадать «это очень частый пароль». Всё это гораздо сдержаннее, чем POST открытого текста, — и это всё равно исходящий запрос. Во вкладке «Сеть» появится обращение к api.pwnedpasswords.com. Отключите сеть — такая проверка должна упасть.

Диапазонный запрос — не «полная анонимность». Префикс сообщает наблюдателю, в какую из 165 корзин попал хеш. Если скрипт страницы скопировал оригинал до отправки префикса, k-анонимность уже не поможет. Поиск по почте и поиск по паролю — разные API: в HIBP v3 для хешированной почты берут префикс из 6 символов, и это другая поверхность продукта. Здесь сравнивается только «есть ли этот пароль в корпусе паролей». Подписка на ящик и мониторинг домена — не та же проверка.

Поэтому «мы используем HIBP» — не то же предложение, что «пароль не покидал устройство». Точная формулировка: оригинал и полный хеш по задумке не отправляют; префикс и один диапазонный запрос уходят. Если вы принимаете, что третья сторона с корпусом узнаёт корзину хеша, это разумный инженерный компромисс. Если требование жёстче — «эта проверка не должна отправить даже префикс», — берите локальный список из следующего раздела и смиритесь с гораздо более узким покрытием.

Локальный список качает только словарь, пароль не отдаёт

Локальная сверка идёт наоборот: сначала на текущий origin скачивают открытый список слабых паролей, затем в скрипте делают поиск по множеству. Во вкладке «Сеть» словарь появиться может. Кандидат из поля ввода — не должен. Сам список — открытые данные. Типичный источник — файл «топ-N из десяти миллионов паролей» в SecLists, коллекции вокруг OWASP / Daniel Miessler. Он отвечает на «первый словарь атакующего возьмёт это?», а не на «строка сидит в ещё не опубликованном сливе».

Проверка в MyPassGen держит эту границу. После открытия страница запрашивает data/leaked-top10k.txt: около 860 строк, по одному паролю в нижнем регистре на строку, в начале — 123456, password, qwerty. Сравнение идёт в браузере: сначала нижний регистр, затем короткий набор вариантов — @ / 4 как a, 0 как o и похожий leet, плюс срез одного-трёх хвостовых цифр — и проверка множества. Попадание помечают как слабый пароль, даже если строка «длинная». Если словарь не загрузился, скрипт откатывается к крошечному встроенному набору (password, 123456 и ещё несколько). На внешний API утечек он не переключается.

Полоска силы — второй локальный расчёт. Пул символов складывается как 26 + 26 + 10 + 32 в зависимости от того, есть ли строчные, прописные, цифры и знаки. Энтропия примерно равна длине, умноженной на log2(пул), затем снижается, если слишком много повторов. Пороги: ниже примерно 40 бит — слабый, ниже 60 — средний, ниже 80 — сильный, от 80 — очень сильный. Длина меньше 8 получает отдельную пометку «коротко». Генератор случайных паролей допускает 6–128 символов, по умолчанию 16. Офлайн-перебор оценивают как 1010 попыток в секунду, онлайн с ограничением частоты — как 103: порядок величины для чтения, не обещание про конкретную видеокарту. События аналитики пишут оценку и факт попадания в список. Сам пароль они не отправляют.

Эти числа можно сверить на этой машине: строки словаря считает редактор или wc -l. Во вкладке «Сеть» должен быть словарь и не должно быть ввода. Это всё равно нельзя записать как «проверили весь интернет». Около 860 строк не закрывают даже открытый Top 10 000 из SecLists, не говоря о корпусе с индексом хешей размером с HIBP. Честный вывод из промаха один: это не частый слабый пароль из этого списка.

Промах — не «безопасно» и не «никогда не утекал»

Локальный список закрывает голову словаря. Пароль всё равно может сидеть в сливе вне списка, в связке для credential stuffing или в догадках под ваш сайт. Нужен новый пароль — сгенерируйте его на этом устройстве. Не оставляйте старое слово и не дописывайте год или восклицательный знак.

Полоска силы не доказывает, что утечки не было

Полоска оценивает пространство перебора. Она не ищет в архиве. Случайный пароль из 20 символов может иметь высокую энтропию и уже лежать в чужом файле утечки. Атакующий не пойдёт по алфавиту с начала — возьмёт готовый список. Наоборот, Password1! часто проходит форму «нужны заглавная, строчная, цифра и знак» и почти всегда стоит в открытом списке слабых паролей. Из-за этой дыры NIST и снял правила состава.

Если страница показывает и оценку силы, и результат по списку, список должен перекрывать полоску: попадание — слабый. Полоска всё равно полезна. Она ловит «слишком коротко», «только один класс символов» или клавиатурный ряд вроде qwerty. Сама по себе она не выдаёт справку «можно оставить». Обычно нужны две фразы: попал в список или короче 8 — меняйте сейчас; промах и достаточно длинный — всё равно не таскайте его по сайтам, для важных аккаунтов напишите новую строку в менеджере паролей или в локальном генераторе.

«Поиск по всей сети сказал, что промах» — тоже не финал. Диапазонный запрос зависит от того, что чужой корпус успел проглотить и как часто его обновляют. Неопубликованные сливы, пароли внутренних систем и варианты, которые ещё не попали в этот набор хешей, не всплывут. Это гораздо шире локальных 860 строк — и всё равно чужая выборка. Пользоваться обоими инструментами можно, если вы различаете, что каждый отправил наружу и что значит отказ.

Сверка на месте: словарь может быть, пароля быть не должно

Шаги ниже не опираются на обещание бренда. Берите одноразовый тестовый пароль — password или временную строку, которой не было ни на одном аккаунте. Живой пароль в демонстрацию не вставляйте.

  1. Откройте инструменты разработчика, вкладку «Сеть» (Network) и включите «Сохранять журнал» / Preserve log. Сначала фильтр Fetch / XHR, затем просмотрите документы и остальные запросы.
  2. Обновите страницу проверки. Должен появиться статический список (на этом сайте — leaked-top10k.txt). Откройте запрос: в ответе по одному паролю на строку, тело запроса пустое.
  3. Введите тестовый пароль в поле и дождитесь результата. Посмотрите новые запросы: в URL, query, JSON и полях формы не должно быть только что набранной строки.
  4. В панели поиска наберите pwnedpasswords, hibp и range/. Схема с локальным списком на эти хосты ходить не должна. Если ходит — страница сделала диапазонный запрос; читайте предыдущий раздел, а не «полностью локально».
  5. Просмотрите запросы аналитики (в пути часто есть matomo или collect). Имена событий могут говорить «слабый / средний / сильный». В значениях не должно быть пароля.
  6. Чтобы сравнить схему с большим корпусом, прогоните тот же одноразовый пароль на странице, которая вызывает HIBP. Должен быть GET на api.pwnedpasswords.com/range/, в пути — пять шестнадцатеричных символов и ничего больше.

Отключите сеть и введите ещё раз. Для локальной схемы это полезная дополнительная сверка: если словарь уже в кэше, сила и попадание всё равно должны считаться; диапазонный запрос должен упасть. Не делайте «ноль запросов» единственной планкой — первый визит обязан скачать словарь, и это не тот трафик, что POST пароля. В предыдущей заметке та же панель служила локальному шифрованию. Здесь смотрите ещё одно: несёт ли какой-нибудь деловой запрос ваш ввод.

Ошибки: зелёная полоска, «весь интернет» и «я уже проверил»

«Полоска зелёная, значит не утекал» не держится. Зелёный описывает пространство символов. Утечка описывает, держит ли уже кто-то ту же строку. Оба утверждения могут быть истинны сразу.

«Написано локальный расчёт, значит из вкладки ничего не ушло» тоже не держится. Локальный список качает словарь. Диапазонный запрос качает корзину хешей. Запрещать нужно оригинал — и полный хеш — как деловые данные. Запрещать каждый HTTP-запрос не требуется.

«В HIBP не нашлось, значит можно ставить тот же пароль на все сайты» — дорогая ошибка. Credential stuffing бьёт одним паролем по многим сайтам. Ему не нужно, чтобы пароль стоял в открытой первой тысяче. Ни локальный список, ни поиск по большому корпусу повторное использование не лечат. Сгенерируйте новый пароль на этом устройстве, возьмите случайный режим с 16 символами или длиннее и храните на каждом сайте свою строку.

Вставить пароль в чат, чтобы коллега «посмотрел, сильный ли», превращает проверку в утечку. Если новый пароль всё же нужно передать другому человеку, короткий секрет кладут в одноразовую ссылку, ключ — после # в адресе. Файл, который расшифруют не один раз, — в шифрование файлов. Страница проверки отвечает на «посмотрите список и полоску сами». Это не канал обмена ключами.

С чего начать сверку

Начните с пароля, который уже собираетесь списать, или с того, что никогда не стоял на настоящем аккаунте. Откройте страницу проверки, посмотрите запрос словаря во вкладке «Сеть», введите строку и убедитесь, что она не ушла. Если попал в список — не оставляйте два символа и не продолжайте им пользоваться. Откройте генератор и создайте пароль на этом устройстве, длина 16 или больше. Промах значит только то, что строки нет в этом открытом наборе слабых паролей. На каждом сайте всё равно храните свой.

Если вопрос на самом деле другой — «был ли этот пароль в известном крупном сливе», — локальных восьмисот с лишним строк мало. Берите инструмент с диапазонным запросом и k-анонимностью и во вкладке «Сеть» смотрите, что ушёл только префикс из 5 символов. Не отдавайте оригинал незнакомой странице «проверки утечек». После обеих сверок помните: инструмент без регистрации не заменяет защиту входа на каждом сайте и не доказывает, что сервер потом не утечёт.

Когда это сделано, на заголовок уже можно ответить. Локальный список утечек доказывает: «похоже ли это на партию, которую атакующие пробуют первой». Поиск пароля по большой сети — если его сделали правильно — доказывает: «есть ли полный хеш в корпусе, который они ведут». Первый выпускает словарь и оставляет пароль внутри. Второй выпускает префикс и оставляет оригинал внутри. Третья схема, которая шлёт оригинал POST-ом, не относится ни к одной из двух.

Частые вопросы

Локальный список не попал — всё равно идти в Have I Been Pwned?

Зависит от того, какое предложение вам нужно. Промах значит только то, что строки нет в этом открытом списке слабых паролей. Если нужно ещё узнать, есть ли она в корпусе хешей HIBP, сделайте отдельный диапазонный запрос и во вкладке «Сеть» убедитесь, что ушёл только префикс из 5 символов. Две проверки держите раздельно. Не склеивайте их в «я уже искал по всему интернету».

Диапазонный запрос отдаёт HIBP мой пароль?

По официальной схеме и тексту Troy Hunt другая сторона получает первые пять символов SHA-1 или NTLM — не пароль и не полный хеш. Совпадение считают в вашем браузере. Это всё равно исходящий запрос. Если с устройства не должен уйти даже префикс, пользуйтесь только локальным списком и принимайте более узкое покрытие.

Нужна ли учётная запись? Уходит ли проверяемый пароль на сервер?

Учётная запись не нужна. В локальной схеме кандидат должен остаться в поле ввода. Уйти может файл словаря и события аналитики без оригинала. Делает ли страница именно это, решает вкладка «Сеть», а не строка «ничего не отправляем» на сайте.

Можно ли верить «офлайн сломают через N лет» на полоске силы?

Это порядок величины при фиксированной скорости перебора, а не замер конкретной видеокарты или атаки словарём. Когда список попал, атакующие по этим часам не пойдут. Читайте это как напоминание, что строка короткая или классов символов мало, — не как гарантию безопасности.