Пример уязвимого входа
В следующем фрагменте кода есть небольшая проблема с безопасностью. Можете ли вы сказать, что не так?
В качестве подсказки давайте посмотрим, сколько времени занимают несколько вызовов isValidCredentials
:
Есть заметная разница между тем, сколько времени занимает [email protected]
электронная почта и [email protected]
или [email protected]
.
Оказывается, проблема в этих строках:
Вернувшись раньше, если совпадения не было, злоумышленник может легко сказать, что у [email protected]
есть учетная запись, а у [email protected]
и [email protected]
нет.
Атаки по времени
Это типичный пример атаки по времени. Это класс атак, при которых время, необходимое вашему приложению для выполнения задачи, приводит к утечке некоторой информации.
В случае входа в систему разница во времени была довольно очевидной даже из одного запроса. Если бы разница была более тонкой, злоумышленник мог бы сделать много запросов в течение длительного времени и усреднить их вместе, чтобы различать разные случаи.
Это большое дело?
Это может показаться пустяком, но, допустим, я пытаюсь найти чью-то личную электронную почту. У меня есть только их имя, и я знаю, что они подписались на ваш сайт.
Я могу попробовать кучу вариантов [email protected]
или lastname{3digitnumber}@gmail.com
и так далее, пока не найду подходящий.
Кроме того, существуют и другие атаки по времени, которые приводят к утечке еще более конфиденциальной информации, о чем мы вскоре поговорим.
Как мы можем это исправить?
Есть несколько стратегий, но самый простой ответ — «убедитесь, что все кодовые пути занимают одинаковое количество времени». Вам не нужно делать это везде, только в чувствительных частях кодовой базы.
Вместо того, чтобы возвращаться раньше, мы могли бы проверить пароль по какому-нибудь хэшу, а затем вернуть false:
Также полезно добавить ограничение скорости, когда это возможно. Если злоумышленнику нужно много запросов, чтобы различать разные случаи, ограничение их скорости может сделать атаку нецелесообразной.
Тайминговые атаки на практике
Недавно в сбросе пароля Lobste.rs была обнаружена хитрая атака по времени. Он использовал тот факт, что базы данных при сравнении двух строк возвращаются раньше, если строки не совпадают.
Итак, проверка“a”.repeat(10000) === “b”.repeat(10000)
должно занять меньше времени, чем“a”.repeat(10000) === “a”.repeat(9999) + “b”
Это означает, что чем больше символов у вас правильно, тем дольше будет длиться звонок. Злоумышленник может попробовать разные префиксы и посмотреть, какой из них занимает больше всего времени, чтобы медленно определить действительный токен сброса пароля.
Эта же уязвимость существует везде, где кто-то проверяет секретное значение непосредственно в базе данных, поэтому, хотя это может показаться довольно теоретическим, определенно есть реальные случаи, о которых сообщалось и которые были устранены.