-
No último segmento, neste módulo, eu quero te mostrar um ataque geral que
-
afeta muitas implementações de algoritmos Mac. E há uma lição legal
-
ser aprendido a partir de um ataque como este. Então, vamos olhar para uma implementação específica
-
de verificação HMAC. Isto acontece por ser uma implementação da biblioteca Keyczar,
-
que passa a ser escrito em Python. Então aqui está o código que é usado para verificar uma
-
tag gerada pelo HMAC. Este código é realmente simplificada. Eu só queria
-
meio que simplificá-la tanto quanto eu puder para obter o ponto de vista. Então, basicamente, o que o
-
entradas são, a chave, a mensagem, e os bytes de tag. A forma como verificar se ele é, nós
-
re-calcular o HMAC da mensagem e então comparar dizem que a 16, resultando
-
bytes. Para as picadas de assinatura reais dadas. Então, isso parece perfeitamente bem.
-
De fato, qualquer um pode implementá-lo assim. E, de fato, muitas pessoas têm implementado
-
-lo assim. O problema é que, se você olhar como a comparação é feita, o
-
comparação, como se poderia esperar, é feita byte a byte. Há um laço dentro do
-
interpretador Python que faz um loop sobre todos os dezesseis bytes. E acontece que o
-
primeira vez que encontra uma desigualdade, o ciclo termina e diz que as cordas são
-
não igual. Eo facto de que as saídas do comparador quando a primeira desigualdade
-
é encontrado introduz um ataque de temporização significativo sobre esta biblioteca. Então deixe-me mostrar-lhe
-
como se poderia atacá-lo. Então, imagine que você é o invasor, e você tem a mensagem m,
-
para os quais você deseja obter uma marca válida. Agora, seu objetivo é atacar um servidor que
-
tem uma chave HMAC segredo armazenado nele. E o servidor expõe uma interface que
-
basicamente leva pares de mensagem MAC. Verifica se o MAC é válido, se o MAC é válido
-
ele faz algo com a mensagem. E se o MAC não é válido, diz rejeitar.
-
Ok, então ele está de volta ao remetente ou a mensagem rejeita. Então, agora este atacante
-
tem a oportunidade de apresentar, basicamente, muita mensagem que aparece e ver se ele
-
pode deduzir as tags da mensagem específica para a qual uma vez atacada. Aqui está
-
como podemos usar a implementação quebrado a partir do slide anterior para fazer exatamente isso.
-
Então, o que o atacante vai fazer é enviar consultas tag muitas mensagens, onde o
-
mensagem é sempre a mesma. Mas com uma tag, ele vai experimentar com lotes e
-
lotes e lotes de marcas diferentes. Assim, na primeira consulta, o que ele vai fazer é apenas
-
apresentar uma tag aleatório juntamente com a mensagem alvo. E ele vai medir o tempo
-
servidor o levou a responder. A próxima consulta que ele vai apresentar, é que ele vai tentar
-
todos os bytes possíveis primeiros para as marcas. Deixe-me explicar o que quero dizer com isso. Assim, o
-
bytes restantes das tags que ele coloca são apenas arbitrárias, realmente não
-
importa o que eles são. Mas para a primeira mordida, o que ele vai fazer é que ele vai apresentar uma tag
-
de partida com um zero bytes. E então ele vai ver se o servidor teve um pouco
-
pouco mais para verificar a marca do que antes. Se o servidor levou exactamente a mesma quantidade
-
de tempo para verificar a tag como no passo um, então ele vai tentar de novo, desta vez com
-
bytes em um. Se ainda o servidor respondeu muito rapidamente, ele vai tentar
-
com conjuntos de bytes de dois. Se o servidor respondeu rapidamente, em seguida, ele vai tentar
-
com conjuntos de bytes de três, e assim por diante até, finalmente, vamos dizer, quando o byte conjuntos de
-
três servidores do exame um pouco mais para responder. O que isto significa é realmente
-
quando se fez a comparação entre o MAC correto eo MAC apresentado pelo
-
atacante. Os dois combinados sobre este byte, ea rejeição aconteceu na segunda
-
bytes. Aha. Então, agora o atacante sabe que a primeira mordida da tag é definido como três
-
e agora ele pode montar exatamente o mesmo ataque na segunda mordida. Então aqui. É
-
vai apresentar o tag. E o segundo, volta aqui. Aqui Isto deve ir aqui. Assim
-
que vai apresentar uma tag quando o segundo byte é definido para zero. E vai
-
medida se este teve um pouco mais do que na etapa dois. Se não, ele é
-
vai mudar isso para ser definido como um, e ele vai medida se o servidor
-
tempo de resposta é um pouco mais do que antes. Eventualmente, vamos dizer, quando ele define
-
isso, eu não sei. Quando o byte é definido para, a 53, digamos, de repente, o
-
servidor demora um pouco mais para responder. O que significa que agora, o
-
comparador acompanhado nos dois primeiros bytes. E agora o atacante soube que o
-
dois primeiros bytes do Mac são três e 53. E agora ele pode seguir em frente e fazer o
-
mesma coisa no terceiro byte e, em seguida, o byte de quarto e assim por diante e assim
-
por diante. Até que, finalmente, o servidor diz que, sim, eu aceito. Você realmente me deu o
-
Mac direito. E então vamos em frente e agir sobre esta mensagem falsa. Isso, atacar o nosso
-
abastecimento. Então este é um belo exemplo de como um ataque de temporização pode revelar o valor
-
de um MAC, o valor correto do MAC. Tipo de byte por byte, até que finalmente,
-
atacante obtém todos os bytes corretos da marca, e então ele é capaz de enganar o
-
servidor em aceitar este par tag mensagem. A razão de eu gostar deste exemplo é
-
esta é uma maneira perfeitamente razoável de implementação de uma rotina de verificação MAC.
-
E ainda, se você direita-lo desta maneira, ele será completamente quebrado. Então o que fazemos? Assim
-
deixe-me mostrar-lhe duas defesas, a primeira defesa, vou escrevê-lo novamente em python
-
é, é como se segue. Na verdade, a biblioteca Keyczar exatamente implementada essa defesa.
-
Este código é realmente retirado da versão atualizada da biblioteca. O primeiro
-
coisa que fazemos é testar se os bytes de assinatura apresentadas pelo atacante são da
-
comprimento correto, dizem, por HMAC isso seria dizer, você sabe 96 bits ou 128 bits, e
-
se não rejeitamos que, como um MAC inválido. Mas agora, se os bytes de assinatura realmente
-
ter o comprimento correto, o que fazemos é implementar nosso comparador própria. E
-
sempre leva a mesma quantidade de tempo para comparar as duas strings. Assim, em particular,
-
este usa a função zip em Python, que, essencialmente, se você está dando
-
lo duas dezesseis cadeias de bytes. Ele vai criar dezesseis pares. De bytes. Por isso, vou
-
apenas criar um, uma lista de dezasseis elementos, onde cada elemento é um par de bytes. Um
-
tomadas a partir da esquerda e uma tomada a partir da direita. E então você volta, você sabe, você
-
percorrer esta lista de pares. Está calcular o XOR do primeiro par, ea
-
ou para o resultado. Em seguida, é calcular o XOR do segundo par, e
-
você ou que para o resultado. E você nota que, se em algum momento neste
-
loop, dois bytes que ser não igual, então o XOR irá avaliar a algo
-
que é diferente de zero. E, portanto, quando se or'ed-lo para o resultado. O resultado
-
também será contagem em zero, e, em seguida, vamos retornar falso, no final do
-
comparação. Assim, o ponto aqui é que agora o comparador sempre leva o mesmo
-
quantidade de tempo. Mesmo se encontra diferença no número de byte três, será
-
continuar executando as cordas ambos até o fim. E só então se
-
retornar os resultados. Portanto, agora o ataque de temporização supostamente é impossível. No entanto,
-
isso pode ser bastante problemático, porque compiladores tentou ser muito útil aqui. Assim
-
compilador otimizado um pode olhar para este código e dizer: ei, espere um minuto. Eu posso
-
realmente melhorar esse código, tornando o final do circuito fechado quatro. Logo que uma incompatível
-
conjunto de bytes é descoberto. E assim, um compilador otimizado pode ser o seu tipo,
-
de, calcanhar de Aquiles quando se trata de tornar os programas de sempre ter a mesma quantidade de
-
tempo. E assim uma defesa diferente, que não é tão amplamente implementado, é tentar
-
esconder do adversário, o que as cordas são realmente estão sendo comparados. Então deixe-me mostrar
-
você que eu quero dizer com isso. Então, novamente, aqui temos o nosso algoritmo de verificação. Por isso
-
toma como entradas, uma chave, uma mensagem, e MAC de um candidato do adversário. E
-
, em seguida, a forma como fazemos a comparação é que em primeiro lugar, calcular o MAC correto em
-
a mensagem. Mas, então, em vez de comparar diretamente o MAC ea assinatura
-
adversário bytes, o que vamos fazer é nós vamos uma vez mais de hash. Então, nós
-
computar um hash aqui do MAC. Nós computar um hash dos bytes de assinatura. Claro que,
-
se estes dois acontecer a ser a mesma, em seguida, os HMACs resultantes será também o
-
mesmo, assim que a comparação será bem sucedida. Mas a questão é agora, se sig
-
bytes acontecer a MAC igual no primeiro byte, mas não sobre os bytes remanescentes.
-
Então, quando fazemos essa camada adicional de hash, é provável que os dois resultando
-
valores são completamente diferentes. E, como resultado, o byte pelo comparador byte vai
-
saída apenas na primeira iteração. O ponto aqui é que o adversário não
-
realmente sabe quais seqüências estão sendo comparados. E, como resultado, ele não pode
-
montar um ataque de temporização que discutimos anteriormente. Ok, então isso é
-
defesa outro. Pelo menos agora, você não está à mercê de um compilador de otimização.
-
lição O principal de tudo isso é que você percebe que as pessoas que ainda são
-
especialistas em cryptolibraries de execução, obter esse material errado. E o código de direito
-
que as palavras perfeitamente bem e ainda é completamente vulnerável a um ataque de temporização
-
que completamente desfazer toda a segurança do sistema. Então a lição aqui é, naturalmente,
-
você não deve inventar o seu próprio crypto mas você não deve mesmo ser
-
implementar sua própria criptografia, porque muito provavelmente ele estará vulnerável para o lado
-
ataques de canal. Basta usar uma biblioteca padrão como OpenSSL. Keyczar é na verdade um
-
boa biblioteca de usar que reduziria as chances de que você está vulnerável a estes
-
tipos de ataques.