Пример уязвимого входа

В следующем фрагменте кода есть небольшая проблема с безопасностью. Можете ли вы сказать, что не так?

В качестве подсказки давайте посмотрим, сколько времени занимают несколько вызовов 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”

Это означает, что чем больше символов у вас правильно, тем дольше будет длиться звонок. Злоумышленник может попробовать разные префиксы и посмотреть, какой из них занимает больше всего времени, чтобы медленно определить действительный токен сброса пароля.

Эта же уязвимость существует везде, где кто-то проверяет секретное значение непосредственно в базе данных, поэтому, хотя это может показаться довольно теоретическим, определенно есть реальные случаи, о которых сообщалось и которые были устранены.