Как безопасно проверить хэши подписи

Как безопасно проверить хэши подписи

25 октября 2022 г.

На днях мой друг поделился со мной этой ссылкой о CVE-2022-43412. Проблема, раскрытая в этом CVE, заключается в том, что Jenkins Generic Webhook Trigger Plugin использовал непостоянную функцию сравнения времени при проверке равенства предоставленных и ожидаемых токенов веб-перехватчиков.

В дополнение к вышеупомянутой CVE существует также CVE-2022-43411, которая представляет собой ту же проблему, но с подключаемым модулем Jenkins Gitlab.

В этом сообщении блога мы объясним, как работает атака, как избежать подобных проблем и что мы делаем в Svix для защиты наших клиентов.

В чем проблема?

Проблема, описанная в этом CVE, использует побочный канал на основе времени для выполнения атаки оракула против проверки хэша.

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

Я знаю, это может звучать как магия, потому что так оно и есть. Однако давайте демистифицируем это, используя более простой пример, и начнем с него.

Что такое атака Oracle на основе времени?

Предположим, что это не веб-перехватчик, а веб-сайт, защищенный паролем. Разработчик, создавший этот веб-сайт, не знаком с безопасностью, поэтому он реализовал ее следующим образом:

const password = 'Secret123'
if (user_provided_password != password) {
  return 'Wrong password!'
}

Теперь давайте более подробно рассмотрим сравнение в условии.

Поскольку мы использовали высокоуровневую функцию, мы можем просто использовать != между строками, но за кулисами происходит то, что она на самом деле сравнивает их посимвольно (ну, на самом деле это сложнее, чем , но предположим, что для простоты).

Итак, наивная реализация может выглядеть так:

// This function assumes the strings are the same length for simplicity
function is_equal(a, b) {
    for (let i = 0; i < a.length; i++) {
        if (a[i] != b[i]) {
            // Can stop iteration, strings are not equal!
            return false;
        }
    }

    return true;
}

Для примера предположим, что наш компьютер очень медленный и выполнение a[i] != b[i] каждый раз занимает секунду.

Глядя на приведенное выше, мы видим, что если пользователь передает Bad123123 в качестве пароля, он попытается сравнить первые символы (B и S< /код>), а поскольку они не равны, сравнение остановится раньше, поэтому вся функция займет 1 секунду.

Хотя, если мы передадим Secret123, вся функция займет 9 секунд, так как она сравнила все символы.

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

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

Мы пробуем A и получаем 1 секунду, B и получаем одну секунду, вплоть до S, где внезапно требуется две секунды. . Это позволяет нам найти первый символ.

Теперь мы можем сделать то же самое для второго персонажа. Мы передаем Sa, что занимает 2 секунды, а затем Sb, что занимает две секунды, вплоть до Se, что занимает 3 секунды, поэтому наш пароль начинается с Se!

Мы можем повторять этот процесс, пока не найдем полный пароль.

Каков правильный способ решить это тогда? Хорошо бы сделать сравнение постоянным временем!

// This function assumes the strings are the same length for simplicity
function is_equal_constant(a, b) {
    let ret = true;

    for (let i = 0; i < a.length; i++) {
        // Putting the && ret at the end, to avoid short-circuiting
        ret = (a[i] != b[i]) && ret;
    }

    return true;
}

С помощью этой функции сравнение всегда занимает одно и то же время, что защищает нас от тайминг-атак!

Примечание. не используйте указанную выше функцию в рабочей среде, так как она может работать не так, как ожидалось. Оптимизация компиляторов может изменить поведение, поэтому важно использовать специально созданные функции сравнения, предоставляемые вашими системными библиотеками, которые уже защищают от этого.

Как это применимо к веб-перехватчикам?

Веб-перехватчики на самом деле не имеют пароля, но у них есть подписи, которые в некотором роде являются динамическими паролями. С помощью веб-перехватчиков вы передаете определенную полезную нагрузку, например:

{
  "foo": "bar"
}

и подписать его секретным ключом таким образом, чтобы его мог подписать только тот, у кого есть ключ. Подпись (например, Vh082qUqkhY7WiBktRKRbP6/c+EYoqtHi/dMULaTKc=) затем передается вместе с полезной нагрузкой, и получатель может убедиться, что отправитель имеет секретный ключ и, таким образом, можно доверять веб-перехватчику.

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

Вышеупомянутая атака по времени не может помочь нам восстановить секретный ключ, используемый для подписи, но может помочь нам найти действительную подпись!

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

Как Svix решает эту проблему?

Безопасность — это сложно. Причина этого в том, что вопросы безопасности не всегда очевидны. Если в вашем коде есть ошибка, вы обычно заметите ее во время тестирования. Хотя с безопасностью вы не всегда знаете, что проверять.

Эта проблема, к сожалению, не может быть устранена на стороне отправителя (Svix), она должна быть устранена на стороне клиента. Поэтому мы не можем решить эту проблему с нашей стороны.

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

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


Подпишитесь на нас в Twitter, GitHub или RSS для получения последних обновлений для сервис веб-перехватчиков Svix или присоединяйтесь к обсуждению в нашем сообществе Slack. р>

Также опубликовано здесь

Фото Филиппа Катценбергера на Unsplash


Оригинал