Что доказывает локальный список слабых паролей — и почему это не поиск по всем утечкам

Страница проверки пишет «нет в списке слабых паролей», и это легко прочитать как «этот пароль ни разу не всплывал ни в одном дампе». Это разные утверждения. Короткий список, который скачивается вместе со страницей, отвечает только на вопрос, похожа ли строка на уже заезженный пароль. Have I Been Pwned отвечает на другой вопрос и ходит по другому пути данных. Ниже сужаем формулировку, которую можно записать в вывод, и даём проверку, которую можно закончить в DevTools.

«Нет в списке» — не «никогда не утекал»

Локальная проверка обычно возвращает одно из двух: совпадение или его отсутствие. Совпадение использовать просто. Строка уже стоит в открытом списке частых слабых паролей, значит вы остаётесь в первой пачке, которую перебирает атакующий. Путаница начинается с «нет в списке»: список «из утечек», значит отсутствие совпадения читают как «чистый».

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

Запишите эту границу, прежде чем решать, что делать дальше. Совпадение — причина сменить пароль. Отсутствие совпадения всё равно оставляет длину, повторное использование и вопрос, сгенерировал ли строку менеджер паролей. Список — фильтр. Это не справка о невиновности.

От какого угадывания защищает список

Атакующие редко идут от a до zzzz…. Два обычных пути — stuffing: взять утёкшую пару логин-пароль и пробовать её на других сайтах, — и онлайн-подбор, который начинается с вершины открытых рейтингов слабых паролей. 123456, password и qwerty стоят в начале этих рейтингов не потому, что «выглядят коротко», а потому что их продолжают выбирать. Несколько попыток часто хватает.

Список частых слабых паролей целится именно в этот слой. Он помечает строки, которые уже заезжены, пока вы ещё можете их сменить. Он не отвечает, насколько велико пространство перебора, и не отвечает, есть ли эта точная строка в каком-то ещё не опубликованном корпусе. Это оценка энтропии и гораздо более крупный корпус утечек. Их не стоит склеивать в один вердикт вместе с «похоже ли это на типичный слабый пароль».

Поэтому список, который сам по себе не особенно длинный, всё равно полезен. Онлайн-вход почти всегда ограничивают по частоте попыток. У атакующего маленький бюджет до блокировки, поэтому сначала пробуют пароли с вершины рейтинга. В NIST SP 800-63B-4 цель blocklist сформулирована так: отсечь пароли, которые с высокой вероятностью угадают до того, как сработает ограничение попыток. Когда список уже закрывает эту цель, дополнительные строки почти ничего не добавляют: онлайн-атака и так душится лимитом. Локальный список частых слабых паролей построен под эту цель. Он не рассчитан на то, чтобы содержать каждый пароль, который когда-либо утекал.

NIST требует сверки всей строки, а не ещё одного набора правил сложности

Национальный институт стандартов и технологий США в SP 800-63B-4 записывает сверку как обязательный шаг для стороны, которая принимает пароль: при создании или смене нужно сравнить всю кандидатную строку с blocklist часто используемых, ожидаемых или уже скомпрометированных паролей. Проверка — не «есть ли внутри словарное слово» и не «не хватает ли символа». Совпадение нужно отклонить и объяснить, почему.

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

NIST также напоминает: после отказа нужно дать подсказку, как выбрать другой пароль, чтобы человек не остановился на переписывании password в Password1. Если локальный список дополнительно пробует регистр, две-три цифры в конце и типичный leetspeak (@ вместо a, 0 вместо o), он целится именно в такие переписывания. Это всё ещё эвристика, а не криптографическое доказательство. P@ssw0rd2026! могут поймать. Переписывание, которого нет в правилах, — нет.

Не запускайте эту проверку на пароле, которым ещё пользуетесь. Если нужно сверить список, возьмите уже списанный старый пароль или одноразовую тестовую строку. Вы проверяете правило и трафик, а не раскрываете живой секрет ещё раз.

Короткий локальный список, запрос по префиксу хеша и полный офлайн-корпус

«Утекал ли этот пароль?» — это как минимум три разных метода. Смешаете их — и «нет в списке» превратится в «никогда не утекал». Разница не в слогане. Разница в том, какие данные покидают устройство и что видит сервер.

Первый метод — короткий локальный список. Страница скачивает открытый текстовый файл в текущую вкладку, скрипт собирает множество в памяти и ищет всю введённую строку плюс несколько вариантов. Исходящий запрос — сам файл списка, а не проверяемый пароль. Покрытие равно числу непустых строк. Возьмите файл leaked-top10k.txt, который MakePwd отдаёт вместе со страницей проверки. В имени написано top10k. Откройте ответ и посчитайте строки сами: сейчас там чуть больше восьмисот частых записей, не десять тысяч и не вся сеть. Если список не загрузился, реализация падает на крошечный встроенный набор (например password и 123456). Покрытие сужается. Сверка по-прежнему остаётся на этом устройстве.

Второй метод — range-запрос Pwned Passwords у Have I Been Pwned. В официальных документах корпус описан как сотни миллионов паролей, которые уже встречались в утечках. Клиент считает SHA-1 (или NTLM) локально и отправляет только первые пять шестнадцатеричных символов на https://api.pwnedpasswords.com/range/{prefix}. Затем сравнивает вернувшиеся суффиксы с полным хешем, который уже посчитал. По задумке ни открытый текст, ни полный хеш не уходят. Это k-анонимность: сервер узнаёт только, в какое из примерно миллиона ведер префиксов вы попали (165). Это всё равно внешний запрос. Запрашивают не сам пароль. В ноябре 2025 года HIBP принял около 1,3 миллиарда уникальных паролей из корпуса credential stuffing Synthient, из них около 625 миллионов для сервиса были новыми. В июне 2026 года добавили около 124 миллионов уникальных паролей из журналов стилеров. Эти цифры показывают, что корпус растёт. Они не значат «проверил один раз — чисто навсегда».

Третий метод — скачать весь корпус на свою машину или во внутреннюю сеть и сверять офлайн. HIBP публикует и такую загрузку. Покрытие близко ко второму методу, но префикс на api.pwnedpasswords.com не уходит. Цена — обновления, место на диске и хеш-индекс, который вы ведёте сами.

Метод Что покидает устройство Что поддерживает «нет совпадения»
Локальный список частых паролей Файл списка; проверяемый пароль не должен Нет в этом списке (и в вариантах, которые умеет скрипт)
Range-запрос HIBP 5-символьный префикс SHA-1 / NTLM Нет в текущем корпусе Pwned Passwords
Полный офлайн-корпус Нет запроса сверки Нет в той копии, которую вы скачали

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

Что можно записать при совпадении и при его отсутствии

Совпадение можно сформулировать жёстко: эта строка уже стоит в открытом списке частых слабых паролей либо это лишь то переписывание, которое список умеет узнать. Продолжаете пользоваться — остаётесь в множестве, которое stuffing и онлайн-подбор пробуют первым. Правильный шаг — сменить и не повторять ту же строку на других сайтах.

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

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

Самая короткая фраза коллеге: совпадение — меняйте сразу; «нет в списке» исключает только этот список. Дальше спросите, не повторяется ли пароль и сгенерирован ли он случайно.

Проверьте на месте: файл списка, затем Network

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

Начните со списка. Откройте DevTools → Network, отфильтруйте запрос, в имени которого есть leaked или top, и сохраните ответ как текст. Посчитайте непустые строки в редакторе. Просмотрите первые строки: там должны быть открытые частые пароли вроде 123456 и password. Число строк, которое вы сами посчитали, — знаменатель фразы «нет в списке». Не пишите «10 000 записей» только потому, что в имени файла есть 10k.

Затем проверьте сам пароль. Приготовьте канарейку, которой не бывает в настоящей работе, например canary-audit-2026-x7k, и введите её в поле проверки. Включите Preserve log и вставьте эту строку в фильтр. Её не должно быть в строке запроса XHR / Fetch, в query и в теле. Её не должно быть в query или теле аналитики. Статика, шрифты и файл списка могут появиться: исходящий список ожидаем. Исходящий проверяемый пароль — провал.

  1. Откройте Network, включите Preserve log, закончите одну проверку, найдите ответ с файлом списка и посчитайте строки.
  2. Запустите проверку ещё раз с паролем-канарейкой и поищите эту строку в фильтре. Совпадение в любом запросе значит, что открытый текст покинул вкладку.
  3. Если совпадений нет, откройте запросы аналитики и убедитесь: заголовок и путь могут быть, полный текст поля ввода — нет.

Этот вывод узкий: в этом запуске проверяемый пароль не покинул текущую вкладку как наблюдаемое HTTP-поле, а покрытие списка равно числу строк, которые вы посчитали. Это не доказывает, что расширение не читало поле ввода, и не доказывает, что скрипт следующей недели поведёт себя так же. Сменили браузер или версию — канарейку стоит поискать снова.

Энтропия и список отвечают на разные вопросы

Страница проверки часто показывает уровень, число бит и отметку о совпадении со списком. Считать их одним баллом — значит путаться, когда бит «нормально», а список сработал, или когда совпадения нет, а строка короткая. Они отвечают на разные вопросы. Они не должны погашать друг друга.

Энтропия спрашивает: если атакующий перебирает алфавит, сколько в среднем это займёт? Обычная формула — длина, умноженная на log2(размер алфавита), затем скидка за повторяющиеся символы или длинные серии одного символа. Если пороги записаны как ≥ 80 бит — Очень надёжный, ≥ 60 — Надёжный, ≥ 40 — Средний, остальное — Слабый, это корзины этой оценки. Это не лабораторное время взлома. Офлайн- и онлайн-шкалы ещё и берут разные скорости: например 1010 попыток в секунду офлайн и 103 онлайн, затем средний случай (половина пространства поиска). Смените скорость — изменится время. Пароль — нет.

Список спрашивает: эту строку уже публично заездили? Число бит он не использует. Совпадение со списком всё равно нужно пометить как слабое, даже если внутри случайно оказались заглавная и символ. Шестисимвольная строка без совпадения даст низкую энтропию, и одной длины хватит, чтобы поставить «Слабый» — к корпусу утечек это не относится. Предупреждение «слабее, чем нужно» короче 8 символов — про длину, а не про базу утечек.

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

Границу удобно отработать на странице, которая открывается сразу

Если нужна страница, где граница написана прямо, начните с проверки сложности MakePwd. Открывается без регистрации и без хранилища паролей. По описанию продукта проверяемый пароль не загружается и не пишется в аналитику. Сверка идёт по открытому списку частых слабых паролей, который скачивается в эту вкладку. Это не Have I Been Pwned и не перебор по всей сети. Совпадение принудительно ставит «Слабый». Для строк длиннее 128 символов выполняется только точное совпадение — без цифр в конце и замен Leet.

Тренируйтесь на одноразовой тестовой строке, не на живом пароле. Держите Network открытым: должны быть файл списка и, возможно, аналитика, но не полный текст поля ввода. Когда нужен новый пароль, генератор тоже открывается сразу. Случайный режим — 6–128 символов, по умолчанию 16, короче 8 получают предупреждение, что так слабее, чем нужно. И генерация, и проверка заканчиваются в браузере. Открытый текст по умолчанию остаётся на этом устройстве.

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

Три вещи, которые стоит запомнить в следующий раз

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

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