1 00:00:00,000 --> 00:00:03,757 No último segmento, neste módulo, eu quero te mostrar um ataque geral que 2 00:00:03,757 --> 00:00:07,615 afeta muitas implementações de algoritmos Mac. E há uma lição legal 3 00:00:07,615 --> 00:00:11,727 ser aprendido a partir de um ataque como este. Então, vamos olhar para uma implementação específica 4 00:00:11,727 --> 00:00:15,941 de verificação HMAC. Isto acontece por ser uma implementação da biblioteca Keyczar, 5 00:00:15,941 --> 00:00:20,003 que passa a ser escrito em Python. Então aqui está o código que é usado para verificar uma 6 00:00:20,003 --> 00:00:23,709 tag gerada pelo HMAC. Este código é realmente simplificada. Eu só queria 7 00:00:23,709 --> 00:00:27,822 meio que simplificá-la tanto quanto eu puder para obter o ponto de vista. Então, basicamente, o que o 8 00:00:27,822 --> 00:00:32,235 entradas são, a chave, a mensagem, e os bytes de tag. A forma como verificar se ele é, nós 9 00:00:32,235 --> 00:00:38,082 re-calcular o HMAC da mensagem e então comparar dizem que a 16, resultando 10 00:00:38,082 --> 00:00:43,271 bytes. Para as picadas de assinatura reais dadas. Então, isso parece perfeitamente bem. 11 00:00:43,271 --> 00:00:47,834 De fato, qualquer um pode implementá-lo assim. E, de fato, muitas pessoas têm implementado 12 00:00:47,834 --> 00:00:52,231 -lo assim. O problema é que, se você olhar como a comparação é feita, o 13 00:00:52,231 --> 00:00:56,740 comparação, como se poderia esperar, é feita byte a byte. Há um laço dentro do 14 00:00:56,740 --> 00:01:01,373 interpretador Python que faz um loop sobre todos os dezesseis bytes. E acontece que o 15 00:01:01,373 --> 00:01:06,297 primeira vez que encontra uma desigualdade, o ciclo termina e diz que as cordas são 16 00:01:06,297 --> 00:01:10,972 não igual. Eo facto de que as saídas do comparador quando a primeira desigualdade 17 00:01:10,972 --> 00:01:16,146 é encontrado introduz um ataque de temporização significativo sobre esta biblioteca. Então deixe-me mostrar-lhe 18 00:01:16,146 --> 00:01:21,257 como se poderia atacá-lo. Então, imagine que você é o invasor, e você tem a mensagem m, 19 00:01:21,257 --> 00:01:26,368 para os quais você deseja obter uma marca válida. Agora, seu objetivo é atacar um servidor que 20 00:01:26,368 --> 00:01:31,230 tem uma chave HMAC segredo armazenado nele. E o servidor expõe uma interface que 21 00:01:31,230 --> 00:01:36,089 basicamente leva pares de mensagem MAC. Verifica se o MAC é válido, se o MAC é válido 22 00:01:36,089 --> 00:01:40,450 ele faz algo com a mensagem. E se o MAC não é válido, diz rejeitar. 23 00:01:40,450 --> 00:01:45,039 Ok, então ele está de volta ao remetente ou a mensagem rejeita. Então, agora este atacante 24 00:01:45,039 --> 00:01:49,685 tem a oportunidade de apresentar, basicamente, muita mensagem que aparece e ver se ele 25 00:01:49,685 --> 00:01:54,274 pode deduzir as tags da mensagem específica para a qual uma vez atacada. Aqui está 26 00:01:54,274 --> 00:01:59,036 como podemos usar a implementação quebrado a partir do slide anterior para fazer exatamente isso. 27 00:01:59,036 --> 00:02:03,661 Então, o que o atacante vai fazer é enviar consultas tag muitas mensagens, onde o 28 00:02:03,661 --> 00:02:08,044 mensagem é sempre a mesma. Mas com uma tag, ele vai experimentar com lotes e 29 00:02:08,044 --> 00:02:12,595 lotes e lotes de marcas diferentes. Assim, na primeira consulta, o que ele vai fazer é apenas 30 00:02:12,595 --> 00:02:17,202 apresentar uma tag aleatório juntamente com a mensagem alvo. E ele vai medir o tempo 31 00:02:17,202 --> 00:02:21,674 servidor o levou a responder. A próxima consulta que ele vai apresentar, é que ele vai tentar 32 00:02:21,674 --> 00:02:25,896 todos os bytes possíveis primeiros para as marcas. Deixe-me explicar o que quero dizer com isso. Assim, o 33 00:02:25,896 --> 00:02:30,011 bytes restantes das tags que ele coloca são apenas arbitrárias, realmente não 34 00:02:30,011 --> 00:02:34,557 importa o que eles são. Mas para a primeira mordida, o que ele vai fazer é que ele vai apresentar uma tag 35 00:02:34,557 --> 00:02:39,392 de partida com um zero bytes. E então ele vai ver se o servidor teve um pouco 36 00:02:39,392 --> 00:02:44,285 pouco mais para verificar a marca do que antes. Se o servidor levou exactamente a mesma quantidade 37 00:02:44,285 --> 00:02:49,062 de tempo para verificar a tag como no passo um, então ele vai tentar de novo, desta vez com 38 00:02:49,062 --> 00:02:52,976 bytes em um. Se ainda o servidor respondeu muito rapidamente, ele vai tentar 39 00:02:52,976 --> 00:02:56,961 com conjuntos de bytes de dois. Se o servidor respondeu rapidamente, em seguida, ele vai tentar 40 00:02:56,961 --> 00:03:01,101 com conjuntos de bytes de três, e assim por diante até, finalmente, vamos dizer, quando o byte conjuntos de 41 00:03:01,101 --> 00:03:05,344 três servidores do exame um pouco mais para responder. O que isto significa é realmente 42 00:03:05,344 --> 00:03:09,484 quando se fez a comparação entre o MAC correto eo MAC apresentado pelo 43 00:03:09,484 --> 00:03:14,334 atacante. Os dois combinados sobre este byte, ea rejeição aconteceu na segunda 44 00:03:14,334 --> 00:03:19,073 bytes. Aha. Então, agora o atacante sabe que a primeira mordida da tag é definido como três 45 00:03:19,073 --> 00:03:23,435 e agora ele pode montar exatamente o mesmo ataque na segunda mordida. Então aqui. É 46 00:03:23,435 --> 00:03:28,519 vai apresentar o tag. E o segundo, volta aqui. Aqui Isto deve ir aqui. Assim 47 00:03:28,519 --> 00:03:32,514 que vai apresentar uma tag quando o segundo byte é definido para zero. E vai 48 00:03:32,514 --> 00:03:36,516 medida se este teve um pouco mais do que na etapa dois. Se não, ele é 49 00:03:36,516 --> 00:03:40,502 vai mudar isso para ser definido como um, e ele vai medida se o servidor 50 00:03:40,502 --> 00:03:44,758 tempo de resposta é um pouco mais do que antes. Eventualmente, vamos dizer, quando ele define 51 00:03:44,758 --> 00:03:48,960 isso, eu não sei. Quando o byte é definido para, a 53, digamos, de repente, o 52 00:03:48,960 --> 00:03:52,677 servidor demora um pouco mais para responder. O que significa que agora, o 53 00:03:52,677 --> 00:03:56,943 comparador acompanhado nos dois primeiros bytes. E agora o atacante soube que o 54 00:03:56,943 --> 00:04:01,056 dois primeiros bytes do Mac são três e 53. E agora ele pode seguir em frente e fazer o 55 00:04:01,056 --> 00:04:05,274 mesma coisa no terceiro byte e, em seguida, o byte de quarto e assim por diante e assim 56 00:04:05,274 --> 00:04:09,175 por diante. Até que, finalmente, o servidor diz que, sim, eu aceito. Você realmente me deu o 57 00:04:09,175 --> 00:04:13,858 Mac direito. E então vamos em frente e agir sobre esta mensagem falsa. Isso, atacar o nosso 58 00:04:13,858 --> 00:04:18,711 abastecimento. Então este é um belo exemplo de como um ataque de temporização pode revelar o valor 59 00:04:18,711 --> 00:04:23,140 de um MAC, o valor correto do MAC. Tipo de byte por byte, até que finalmente, 60 00:04:23,140 --> 00:04:28,094 atacante obtém todos os bytes corretos da marca, e então ele é capaz de enganar o 61 00:04:28,094 --> 00:04:32,640 servidor em aceitar este par tag mensagem. A razão de eu gostar deste exemplo é 62 00:04:32,640 --> 00:04:37,186 esta é uma maneira perfeitamente razoável de implementação de uma rotina de verificação MAC. 63 00:04:37,186 --> 00:04:41,941 E ainda, se você direita-lo desta maneira, ele será completamente quebrado. Então o que fazemos? Assim 64 00:04:41,941 --> 00:04:46,509 deixe-me mostrar-lhe duas defesas, a primeira defesa, vou escrevê-lo novamente em python 65 00:04:46,509 --> 00:04:51,020 é, é como se segue. Na verdade, a biblioteca Keyczar exatamente implementada essa defesa. 66 00:04:51,020 --> 00:04:55,588 Este código é realmente retirado da versão atualizada da biblioteca. O primeiro 67 00:04:55,588 --> 00:05:00,328 coisa que fazemos é testar se os bytes de assinatura apresentadas pelo atacante são da 68 00:05:00,328 --> 00:05:04,896 comprimento correto, dizem, por HMAC isso seria dizer, você sabe 96 bits ou 128 bits, e 69 00:05:04,896 --> 00:05:09,421 se não rejeitamos que, como um MAC inválido. Mas agora, se os bytes de assinatura realmente 70 00:05:09,421 --> 00:05:13,466 ter o comprimento correto, o que fazemos é implementar nosso comparador própria. E 71 00:05:13,466 --> 00:05:17,895 sempre leva a mesma quantidade de tempo para comparar as duas strings. Assim, em particular, 72 00:05:17,895 --> 00:05:22,159 este usa a função zip em Python, que, essencialmente, se você está dando 73 00:05:22,159 --> 00:05:28,116 lo duas dezesseis cadeias de bytes. Ele vai criar dezesseis pares. De bytes. Por isso, vou 74 00:05:28,116 --> 00:05:32,666 apenas criar um, uma lista de dezasseis elementos, onde cada elemento é um par de bytes. Um 75 00:05:32,666 --> 00:05:37,051 tomadas a partir da esquerda e uma tomada a partir da direita. E então você volta, você sabe, você 76 00:05:37,051 --> 00:05:41,326 percorrer esta lista de pares. Está calcular o XOR do primeiro par, ea 77 00:05:41,326 --> 00:05:45,492 ou para o resultado. Em seguida, é calcular o XOR do segundo par, e 78 00:05:45,492 --> 00:05:49,932 você ou que para o resultado. E você nota que, se em algum momento neste 79 00:05:49,932 --> 00:05:54,207 loop, dois bytes que ser não igual, então o XOR irá avaliar a algo 80 00:05:54,207 --> 00:05:58,577 que é diferente de zero. E, portanto, quando se or'ed-lo para o resultado. O resultado 81 00:05:58,577 --> 00:06:02,632 também será contagem em zero, e, em seguida, vamos retornar falso, no final do 82 00:06:02,632 --> 00:06:06,578 comparação. Assim, o ponto aqui é que agora o comparador sempre leva o mesmo 83 00:06:06,578 --> 00:06:10,720 quantidade de tempo. Mesmo se encontra diferença no número de byte três, será 84 00:06:10,720 --> 00:06:15,479 continuar executando as cordas ambos até o fim. E só então se 85 00:06:15,479 --> 00:06:20,244 retornar os resultados. Portanto, agora o ataque de temporização supostamente é impossível. No entanto, 86 00:06:20,244 --> 00:06:25,256 isso pode ser bastante problemático, porque compiladores tentou ser muito útil aqui. Assim 87 00:06:25,256 --> 00:06:30,143 compilador otimizado um pode olhar para este código e dizer: ei, espere um minuto. Eu posso 88 00:06:30,143 --> 00:06:35,107 realmente melhorar esse código, tornando o final do circuito fechado quatro. Logo que uma incompatível 89 00:06:35,107 --> 00:06:39,378 conjunto de bytes é descoberto. E assim, um compilador otimizado pode ser o seu tipo, 90 00:06:39,378 --> 00:06:43,930 de, calcanhar de Aquiles quando se trata de tornar os programas de sempre ter a mesma quantidade de 91 00:06:43,930 --> 00:06:48,482 tempo. E assim uma defesa diferente, que não é tão amplamente implementado, é tentar 92 00:06:48,482 --> 00:06:52,978 esconder do adversário, o que as cordas são realmente estão sendo comparados. Então deixe-me mostrar 93 00:06:52,978 --> 00:06:57,417 você que eu quero dizer com isso. Então, novamente, aqui temos o nosso algoritmo de verificação. Por isso 94 00:06:57,417 --> 00:07:01,740 toma como entradas, uma chave, uma mensagem, e MAC de um candidato do adversário. E 95 00:07:01,740 --> 00:07:06,156 , em seguida, a forma como fazemos a comparação é que em primeiro lugar, calcular o MAC correto em 96 00:07:06,156 --> 00:07:10,407 a mensagem. Mas, então, em vez de comparar diretamente o MAC ea assinatura 97 00:07:10,407 --> 00:07:14,933 adversário bytes, o que vamos fazer é nós vamos uma vez mais de hash. Então, nós 98 00:07:14,933 --> 00:07:19,459 computar um hash aqui do MAC. Nós computar um hash dos bytes de assinatura. Claro que, 99 00:07:19,459 --> 00:07:23,765 se estes dois acontecer a ser a mesma, em seguida, os HMACs resultantes será também o 100 00:07:23,765 --> 00:07:27,794 mesmo, assim que a comparação será bem sucedida. Mas a questão é agora, se sig 101 00:07:27,794 --> 00:07:31,690 bytes acontecer a MAC igual no primeiro byte, mas não sobre os bytes remanescentes. 102 00:07:31,690 --> 00:07:35,607 Então, quando fazemos essa camada adicional de hash, é provável que os dois resultando 103 00:07:35,607 --> 00:07:39,675 valores são completamente diferentes. E, como resultado, o byte pelo comparador byte vai 104 00:07:39,675 --> 00:07:43,693 saída apenas na primeira iteração. O ponto aqui é que o adversário não 105 00:07:43,693 --> 00:07:47,258 realmente sabe quais seqüências estão sendo comparados. E, como resultado, ele não pode 106 00:07:47,258 --> 00:07:50,809 montar um ataque de temporização que discutimos anteriormente. Ok, então isso é 107 00:07:50,809 --> 00:07:55,447 defesa outro. Pelo menos agora, você não está à mercê de um compilador de otimização. 108 00:07:55,447 --> 00:08:00,027 lição O principal de tudo isso é que você percebe que as pessoas que ainda são 109 00:08:00,027 --> 00:08:04,490 especialistas em cryptolibraries de execução, obter esse material errado. E o código de direito 110 00:08:04,490 --> 00:08:08,351 que as palavras perfeitamente bem e ainda é completamente vulnerável a um ataque de temporização 111 00:08:08,351 --> 00:08:12,310 que completamente desfazer toda a segurança do sistema. Então a lição aqui é, naturalmente, 112 00:08:12,310 --> 00:08:15,775 você não deve inventar o seu próprio crypto mas você não deve mesmo ser 113 00:08:15,775 --> 00:08:19,785 implementar sua própria criptografia, porque muito provavelmente ele estará vulnerável para o lado 114 00:08:19,785 --> 00:08:23,546 ataques de canal. Basta usar uma biblioteca padrão como OpenSSL. Keyczar é na verdade um 115 00:08:23,546 --> 00:08:27,605 boa biblioteca de usar que reduziria as chances de que você está vulnerável a estes 116 00:08:27,605 --> 00:08:28,447 tipos de ataques.