https://a.storyblok.com/f/270183/56949/f19a5a9cd5/social_google-authenticator_1200x627.png

Crie um “Google Authenticator” a partir de um telefone fixo com a Vonage

Publicado em May 7, 2021

Tempo de leitura: 23 minutos

Adoramos a autenticação de dois fatores (2FA) — ela torna o login muito mais seguro, pois combina uma senha memorizada com um código de acesso único gerado pelo seu celular. O problema com uma boa segurança, porém, é que fica muito fácil ficar sem acesso à conta.

Imagine que você está longe de casa — de férias, talvez, ou em uma viagem de negócios para uma cidade distante. É para isso que a autenticação de dois fatores (2FA) foi criada; você pode usar aquele computador compartilhado no saguão do hotel sem ficar com muito medo de keyloggers. Os hackers podem conseguir sua senha, mas ainda assim não conseguirão acessar suas coisas sem o celular na sua mão!

An example image of the authenticator

Mas e se você não tiver seu celular? E se ele se perder, se danificar ou for roubado? Bem, para começar, você vai querer ligar para a sua seguradora… mas os dados de contato estão no seu celular e no e-mail como backup… e você não consegue acessar seu e-mail sem o celular, já que usa a autenticação de dois fatores (2FA)! 😱

E se você pudesse acessar sua senha de autenticação de duas etapas (2FA) como um serviço remoto? Você poderia ligar para um número, digitar seu PIN e ouvir os dígitos sendo lidos para você.

Contexto tecnológico

Embora as primeiras implementações fossem proprietárias, existe um padrão aberto da Iniciativa para Autenticação Aberta (OATH) para senhas de uso único baseadas em tempo (TOTP), especificado na RFC 6238. Esse padrão utiliza um segredo pré-compartilhado e o número de intervalos de 30 segundos desde 01/01/1970 00:00:00 UTC, calcula um hash criptográfico e transforma-o em um número de seis dígitos que não pode ser previsto sem conhecer o segredo.

O que torna isso prático de usar, no entanto, é um esquema de URI definido pelo Google. Eles têm o seguinte formato: otpauth://totp/Example:totp@example.com?secret=KVKFKRCPNZQUYMLXOVYDSQKJKZDTSRLD&issuer=Example

Normalmente, esses URIs são codificados como um código QR, assim:

QR Code example for authentication.

Pré-requisitos

Há algumas coisas de que você vai precisar para este exemplo:

  • Google Authenticator (Android/iOSou qualquer aplicativo OATH TOTP semelhante)

  • Um serviço compatível com a autenticação de dois fatores (como uma Account do Google)

  • Um ngrok Account

  • A Heroku Account

  • ngrok instalado localmente (usei a versão 2.3.35)

  • node.js instalado localmente (usei a versão 12.6.1)

Applications

Vamos usar o Node.js neste exemplo porque ele facilita muito a execução de um serviço web simples. Além disso, há uma implementação bastante boa da lógica de senha de uso único de que precisamos: otplib.

Primeiro, precisamos instalar as bibliotecas necessárias, o que faremos com o npm.

npm install express body-parser otplib

Agora, insira o código a seguir em um arquivo chamado totp.js. Vamos começar com o PIN de acesso e o segredo compartilhado, que é o mesmo do código QR acima, e importar o otplib.

const totp = require('otplib');

// Hardcoded secrets
const secret = 'KVKFKRCPNZQUYMLXOVYDSQKJKZDTSRLD';
const pin = '1234';

Vamos criar um simples serviço web Node.js Express , usando a Voice API da Vonage para atender a chamada e retornar um Nexmo Call Control Object (NCCO), instruindo a API a usar a conversão de texto em fala para reproduzir uma frase e, em seguida, aguardar a entrada do usuário pelo teclado do telefone. Este é um sistema de Resposta Interativa de Voz (IVR) muito simples, mas não vamos nos aprofundar aqui no funcionamento da Voice API. Se você quiser entender melhor o que esse código está fazendo, dê uma olhada neste este tutorial.

const app = require('express')()
const bodyParser = require('body-parser')

app.use(bodyParser.json())

const onInboundCall = (request, response) => {
  const ncco = [
    {
      action: 'talk',
      text: 'Please enter your PIN, followed by a hash.'
    },
    {
      action: 'input',
      eventUrl: [`${request.protocol}://${request.get('host')}/webhooks/passcode`]
    }
  ]

  response.json(ncco)
}

Agora, a parte crucial: verifique o PIN digitado pelo usuário. Se estiver correto, obteremos a senha atual e a leremos em voz alta para ele.

const onInput = (request, response) => {
  const dtmf = request.body.dtmf;
  if (dtmf === pin) {
    const token = totp.authenticator.generate(secret);
    const slow = token.split('').join('. ');

    const ncco = [{
      action: 'talk',
      text: `Passcode is ${slow}. Repeat. ${slow}.`
    }]

    response.json(ncco)
  } else {
    const ncco = [{
      action: 'talk',
      text: `Incorrect PIN. Goodbye.`
    }]

    response.json(ncco)
  }
}

Por fim, associamos as funções que acabamos de definir aos métodos/caminhos HTTP e iniciamos o aplicativo para que ele fique à escuta em port 3000.

const PORT = 3000

app
  .get('/webhooks/answer', onInboundCall)
  .post('/webhooks/passcode', onInput)

app.listen(PORT)

É isso aí! Agora você pode executar isso com o comando `node totp.js` e testá-lo acessando http://localhost:3000/webhooks/answer no seu navegador — ele retornará o objeto JSON da onInboundCall função que acabamos de definir!

Implantação local com o ngrok

Bem, é bom que algo esteja funcionando, mas não adianta muito se só pudermos acessá-lo na nossa máquina local!

O ngrok oferece uma maneira excelente de configurar um redirecionador dinâmico para disponibilizar nosso pequeno serviço na internet. Cadastre-se no site — basta um Account gratuito — e, em seguida, execute:

ngrok authtoken

Isso salvará as credenciais da sua conta localmente; em seguida, você poderá configurar o redirecionamento de HTTP para a porta 3000 (a que usamos acima) executando:

ngrok http 3000

An image example of Ngrok running

Anote os URIs exibidos, pois eles serão específicos do seu serviço e mudarão sempre que o ngrok for executado.

Mais uma vez, podemos testar isso no nosso navegador acessando: https://bd934ed5.ngrok.io/webhooks/answer

Observação: você precisará usar o URI fornecido pelo ngrok.

O ngrok também oferece HTTPS gratuito, então nossa conexão será segura — não é demais?

Configuração das APIs da Vonage

Ainda não fazer fazernada, no entanto. É nessa parte que a coisa fica interessante.

Primeiramente, precisamos criar um novo aplicativo da Voice API. Acesse a aba “Seus aplicativos” do painel de controle das APIs da Vonage e clique no grande botão “Criar um novo aplicativo”:

An example of the Vonage Dashboard

Digite um nome como “Exemplo de senha TOTP” e gere um par de chaves para que ele tenha acesso à API:

An example of generating a keypair to have API access

Em seguida, ative o recurso “Voice” e configure o evento (https://bd934ed5.ngrok.io/webhooks/passcode) e a resposta (https://bd934ed5.ngrok.io/webhooks/answer) com os URIs do ngrok que você anotou acima. Certifique-se de usar seus próprios URIs do ngrok. Observe que o URI do evento usa HTTP POST; portanto, você precisará selecionar essa opção no menu suspenso:

Choosing the capabilities and setting webhoosk for your Vonage Application

Como alternativa, se você preferir usar uma interface de linha de comando (CLI), pode criar um aplicativo assim.

Instale a CLI do Vonage globalmente com este comando:

npm install @vonage/cli -g

Em seguida, configure a CLI com sua chave e seu segredo da API da Vonage. Você pode encontrar essas informações no Painel do Desenvolvedor.

vonage config:set --apiKey=VONAGE_API_KEY --apiSecret=VONAGE_API_SECRET

Crie um novo diretório para o seu projeto e acesse-o com o comando `cd`:

mkdir my_project
CD my_project

Agora, use a CLI para criar um aplicativo da Vonage.

vonage apps:create ✔ Application Name … theoretical_felidae ✔ Select App Capabilities › Voice ✔ Create voice webhooks? … yes ✔ Answer Webhook - URL … https://bd934ed5.ngrok.io/webhooks/answer ✔ Answer Webhook - Method › GET ✔ Event Webhook - URL … https://bd934ed5.ngrok.io/webhooks/passcode ✔ Event Webhook - Method › POST ✔ Allow use of data for AI training? Read data collection disclosure - https://help.nexmo.com/hc/en-us/articles/4401914566036 … yes

Para poder ligar para esse serviço, precisamos de um número externo. Crie um usando “Numbers” -> “Comprar números” no painel de controle:

Screenshot showing example of buying a number in Vonage Dashboard

Mais uma vez, para os fãs da CLI, há a opção de pesquisar primeiro números com serviço de voz (por exemplo, nos EUA):

vonage numbers:search US

Então compre um da lista:

vonage numbers:buy [NUMBER] [COUNTRYCODE]

Por fim, precisamos vincular esse número ao aplicativo. Se você acessar “Meus Applications” no painel e clicar no seu aplicativo TOTP, deverá ver uma linha na parte inferior para inserir o seu número e um botão “Vincular” abaixo de “Gerenciar”:

Screenshot showing how to link a number to your application

Clique em “Link” e confirme, se necessário:

Screenshot showing confirmation of linking number to application

Não se preocupem, exército da CLI, também existe um comando para isso:

vonage apps:link APPLICATION_ID --number=YOUR_VONAGE_NUMBER

Existem também comandos úteis caso você não se lembre do número de telefone (vonage numbers) ou o UUID do aplicativo (vonage apps).

Agora temos nosso serviço vinculado a um número de telefone. Se ligarmos para esse número, isso acionará o /webhooks/answer endpoint, e o NCCO retornado acionará a conversão de texto em fala para reproduzir a frase “Digite seu PIN, seguido de um cerquilha.” e, em seguida, aguardará a entrada do teclado do telefone. Digite “1234#” no teclado, e isso será enviado para o /webhooks/passcode ponto de extremidade, que lerá em voz alta a senha de seis dígitos.

Digitalize o código QR na parte superior desta postagem do blog no Google Authenticator e você verá que os códigos coincidem perfeitamente!

Implantação global com o Heroku

É bom que tenhamos isso funcionando, mas não é muito prático mantê-lo rodando no seu computador — ele vai parar se você desligá-lo e, se estiver viajando, é improvável que você deixe um computador ligado em casa! Portanto, claramente será melhor se pudermos mantê-lo funcionando em algum lugar na internet.

O Heroku é ótimo para isso, permitindo a implantação e hospedagem simples de serviços web. Um Account gratuito já é suficiente, então vá e se cadastre uma e configure-a (com o Git e a CLI do Heroku). Eu espero.

Alterações no código

O Heroku atribuirá uma porta aleatória para a aplicação escutar, então não podemos simplesmente usar a 3000. Precisamos fazer essa alteração de uma linha para totp.js para que ela seja obtida do ambiente:

const PORT = process.env.PORT || 3000

É necessária outra alteração no package.json arquivo para que o npm start comando funcione, pois, caso contrário, o Heroku não saberá como iniciar nosso aplicativo! Basta adicionar o node totp.js comando que usamos localmente ao elemento `scripts`. O código completo package.json agora deve ficar mais ou menos assim:

{
  "name": "totp",
  "version": "1.0.0",
  "description": "One Time Password by phone",
  "main": "totp.js",
  "dependencies": {
    "body-parser": "^1.19.0",
    "express": "^4.17.1",
    "nexmo": "^2.6.0",
    "otplib": "^12.0.1"
  },
  "devDependencies": {},
  "scripts": {
    "start": "node totp.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Russ Williams",
  "license": "ISC"
}

Configurando o controle de versão do Git

Precisamos usar o Git para fazer a implantação no Heroku; além disso, é obviamente uma boa prática ter um controle de versão para qualquer projeto de desenvolvimento. Por enquanto, vamos nos limitar a um repositório local, mas o GitHub é gratuito e manterá seu código seguro, ao mesmo tempo em que o disponibiliza para você de qualquer lugar do mundo.

Primeiro, crie um repositório:

git init

Em seguida, adicione os arquivos de origem de que precisaremos:

git add totp.js package.json private.key

Por fim, precisamos confirmar essas alterações:

git commit -m"Initial release"

Implantação no Heroku

Primeiro, precisamos criar um novo aplicativo no Heroku:

heroku create

Isso atribuirá ao seu novo aplicativo um nome gerado aleatoriamente, algo como lit-spire-15244. O heroku create comando configura um repositório remoto (por exemplo, https://git.heroku.com/lit-spire-15244.git) para o qual podemos enviar código.

Para implantar o aplicativo, precisamos usar o Git novamente para fazer o push para aquele repositório remoto:

git push heroku master

Isso enviará o código para o Heroku e acionará uma implantação. Internamente, será executado npm start e informará um status como https://lit-spire-15244.herokuapp.com/ deployed to Heroku. Se você usar essa URI, https://lit-spire-15244.herokuapp.com/webhooks/answer, no meu caso, você deverá ver que o serviço já está em execução. Mais uma vez, temos HTTPS gratuito, o que é ótimo.

Se você tiver problemas ou apenas quiser saber o que está acontecendo, pode consultar os logs do serviço com o comando:

heroku logs --tail

Atualize o aplicativo da Vonage

Por fim, precisamos atualizar o painel de controle das APIs da Vonage. Vá até a aba “Seus Applications”, selecione o aplicativo TOTP, clique em “Editar” e altere as URIs:

Screenshot showing update webhooks

Próximos passos

Como faço para obter a senha dos meus accounts?

Infelizmente, o Google Authenticator e a maioria dos aplicativos semelhantes não permitem isso. Depois de escanearem um código QR, eles não oferecem nenhuma maneira de recuperar o segredo.

Para contas do G-Suite/Google (por exemplo, Gmail), há uma opção “Alterar telefone” na página de configuração da autenticação de duas etapas (2FA), que permite obter um novo código QR. Para a maioria dos outros serviços, você precisará desativar e, em seguida, reativar a autenticação de duas etapas (2FA), ou solicitar ao administrador do sistema que faça isso por você — essencialmente o mesmo processo que substituir seu celular.

Fazer uma captura de tela e escanear o código QR no aplicativo permitirá que você extraia o segredo e o utilize neste aplicativo.

Como faço para obter a senha de um código QR?

Use um aplicativo genérico de leitura de códigos QR para obter o URI — há muitos disponíveis para todos os celulares, e pode até haver um integrado ao aplicativo de câmera do seu celular. Como alternativa, você pode usar um site como https://webqr.com/ para escanear uma foto.

O segredo de que você precisa é a sequência de letras maiúsculas entre “secret=” e o “&” na URI: otpauth://totp/Example:totp@example.com?secret=KVKFKRCPNZQUYMLXOVYDSQKJKZDTSRLD&issuer=Example

Para onde podemos levar isso?

Existem várias maneiras de ampliar este aplicativo de exemplo:

  • Exigir o uso de segredos codificados diretamente no código não é a melhor opção; seria muito melhor recuperá-los de um banco de dados no lado do servidor

  • Não há proteção contra ataques de força bruta ao seu PIN se alguém estiver disposto a fazer 10.000 chamadas para este aplicativo; portanto, seria útil implementar algum tipo de limitação de taxa

  • É um desperdício ter um número de telefone só para um segredo; por isso, poderíamos criar um sistema de menu IVR (“Pressione 1 para a senha do Gmail, pressione 2 para…”)

  • Os códigos de acesso têm validade limitada; portanto, se faltar apenas alguns segundos para que o código mude, provavelmente devemos usar a função de conversão de texto em fala para informar isso e aguardar o próximo código, em vez de ler um código já expirado. É melhor prolongar a ligação por alguns segundos do que ter que rediscar e tentar novamente

  • Extrair manualmente segredos de códigos QR é um saco, e existem módulos do Node.js (por exemplo, qrcode-reader) que podem fazer isso por nós. Se estivéssemos armazenando os segredos do aplicativo em um banco de dados, poderíamos adicionar um front-end web simples para fazer o cadastro a partir de uma captura de tela (por exemplo, este guia do Google)

  • … ou por meio do acesso à câmera do celular e um pouco de código HTML5 para capturar uma imagem (por exemplo, getUserMedia) ou até mesmo analisar o código QR (por exemplo, este tutorial ou html5-qrcode) e chamar o serviço web de inscrição

Espero que isso tenha lhe dado algumas ideias sobre como você pode usar as APIs da Vonage com a autenticação de dois fatores.

Compartilhar:

https://a.storyblok.com/f/270183/200x267/a8435a2b98/russ-williams.png
Russ Williams

Russ has been arguing with computers since 1985, and now mostly wins the fights. He has worked in video games, defence and investment banking, and joined the Vonage team four days before the Coronavirus lockdown. He enjoys travel, poker, games of all sorts, science fiction, and is easily dist... ooh, squirrel!