Сколько стоит пароль на Raspberry Pi
Страницы статистики здесь можно закрыть паролем. Вычисление хеша этого пароля — единственная операция в этой службе, которая должна быть медленной: именно это делает украденный хеш дорогим для взлома. Вопрос в том, насколько медленной, на этом железе.
Измерено на машине, где работает этот сайт, PHP 8.4.21 на aarch64:
PASSWORD_DEFAULT | 560 мс | (даёт cost 12) |
| cost 12 | 595 мс | |
| cost 11 | 277 мс | |
| cost 10 | 138 мс |
Параметр стоимости у bcrypt — это показатель степени: каждый шаг удваивает работу. Измерения показывают ровно это удвоение, что хороший знак: ничто постороннее не вмешивается.
Почему значение по умолчанию здесь неверный выбор
PHP поднял стоимость bcrypt по умолчанию с 10 до 12. На сервере в дата-центре это разумное повышение — несколько десятков миллисекунд. На маленькой плате ARM это больше половины секунды чистого процессора, на машине, которая в это же время рисует изображения счётчиков для всех остальных.
Полсекунды на один вход плохи сами по себе. Хуже они как приглашение: точку входа может вызвать кто угодно, и каждый вызов съедает 560 мс единственного процессора, обслуживающего весь сайт. Так проверка пароля становится самым дешёвым способом перегрузки из здесь имеющихся.
Поэтому стоимость закреплена на 10, а не оставлена значению по умолчанию. Это намеренно слабее того, что PHP выбирает сегодня, и это стоит сказать прямо, а не закапывать: хеш со стоимостью 10 вчетверо дешевле взломать, чем со стоимостью 12. Выкупает это то, что пароль на самом деле защищает — видимость страницы с числами посещений, не учётную запись, не деньги, не личность. За ней нет ничего, чем можно завладеть.
Часть, которую легко упустить
PASSWORD_DEFAULT — по замыслу подвижное значение. Код, написанный годы назад и использующий его, будет молча становиться медленнее с каждым обновлением PHP: тот же исходник, тот же ввод, кратное время работы. Так и задумано, и для большинства программ это правильно.
Неправильно это только тогда, когда машина не может это вынести, и ничто не предупреждает, когда не может. Обновление проходит, тесты проходят, страница по-прежнему работает. Просто занимает на полсекунды дольше, и на это число никто не смотрит, пока не пойдёт и не измерит.