2013-08-09 1 views
3

Я пишу приложение с NodeJS, которое использует два токена с кодировкой Base64 для аутентификации пользователей. Два токена, когда XORed, должны соответствовать третьему токену, который хранится в базе данных.Сравнение буферов NodeJS, избегая при этом временных атак.

Это то, что я сейчас:

function verifyTokens(encodedTokens) { 
    var similarity = 0; 
    var buffers = encodedTokens.map(base64.decode); 
    for (i = 0; i < TOKEN_LENGTH; i++) { 
     if ((buffers[0][i]^buffers[1][i]) === buffers[2][i]) { 
      similarity += 1; 
     } 
    } 
    return (similarity === TOKEN_LENGTH); 
} 

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

Другим решением для работы с буферами, которые попались на глаза, является node-buffertools, но он использует memcmp для сравнения буферов (которые, как я понимаю, небезопасен).

Каков наилучший способ сравнить два буфера XORed с третьим буфером, который позволяет избежать временных атак? Я бы предпочел решение только для JavaScript над расширением C++.

+0

Не знаю ответа на «лучший способ сравнить два буфера XORed», но вы можете потратить дополнительное время перед возвратом. Разве это невозможно? – randunel

+0

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

+0

Да, я представляю, как сделать некоторое тестирование, чтобы узнать, как долго выполняется операция XOR, и добавив оболочку setTimeout, которая гарантирует, что функция вернется через некоторое время (в обоих случаях) – Plato

ответ

3

Вы можете добавить полученное булево вместо:

function verifyTokens(encodedTokens) { 
    var buffers = encodedTokens.map(base64.decode); 
    var similarity = 0; 

    for (var i = 0; i < TOKEN_LENGTH; i++) { 
     similarity += (buffers[0][i]^buffers[1][i]) === buffers[2][i]); 
    } 

    return similarity === TOKEN_LENGTH; 
} 

Хотя V8 может оптимизировать это и исказить результаты. Вы можете проверить это самостоятельно. Сначала я проверил бы encodedTokens.map(base64.decode).

+0

Это выглядит для меня хорошим улучшением. Как я должен подходить к тестированию для временных векторов атаки? Является ли простой повторный тест достаточно точным или читает исходный код только в полном объеме? – molf

+0

@molf: Используйте контрольную отметку. Источник, вероятно, не будет слишком полезен. – Blender

0

Не могли бы вы XOR все три токена и сравнить с нолем?

var zeroes = new Buffer(Array(32)); // zero fills, not sure encoding 
function verifyTokens(encodedTokens) { 
    var buffers = encodedTokens.map(base64.decode); 
    var xor1 = buffers[0]^buffers[1]; 
    var xor2 = xor1^buffers[2]; 
    if(xor2.toString() === zeroes.toString()){ 
    // there may be a better comparison operator 
    // buf1 === buf2 seems to always return false with different encodings 
    return true; 
    } else { 
    return false; 
    } 
} 
3
function verifyTokens(encodedTokens) { 
    var similarity = 0; 
    var buffers = encodedTokens.map(base64.decode); 
    for (i = 0; i < TOKEN_LENGTH; i++) { 
     similarity |= (buffers[0][i]^buffers[1][i]) | (buffers[1][i]^buffers[2][i]); 
    } 
    return similarity === 0; 
} 

Вероятно, то же самое, но люди, как правило, don't trust операторы сравнения.

 Смежные вопросы

  • Нет связанных вопросов^_^