Secking WebViews with Chrome Custom Tabs

Plaid empowers innovators in the fintech space by providing them with access to financial data via a uniform API. A fim de ajudar os usuários finais a conectar seus dados bancários com aplicativos fintech, o Plaid desenvolveu Link, um módulo drop-in que lida com validação credencial, autenticação multi-fator e tratamento de erros para todos os bancos suportados.

os desenvolvedores do Android tiveram que abrir URLs de ligação em WebViews. Todos os aplicativos que queriam usar o Link exigiam muito esforço de desenvolvedor e, sem padronização, havia necessariamente bugs em algumas das implementações. A fim de melhorar a experiência do desenvolvedor, recentemente lançamos um SDK tornando a WebView fácil de integrar em qualquer aplicativo com algumas linhas de código.

Adicionalmente, as vistas Web não são completamente seguras para os utilizadores finais que introduzem informações sensíveis no fluxo de ligações. A fim de tornar o nosso SDK o mais seguro possível, nós o implementamos usando abas personalizadas Chrome em vez de WebViews Android. Neste artigo explicamos por que tomamos essa decisão e como superamos as questões técnicas que encontramos ao longo do caminho.

avaliando as nossas opções

como SDK, o nosso código funciona dentro das aplicações de outros programadores, e, por sua vez, os seus processos de Aplicação. Para executar a aplicação web de Link em uma WebView, Javascript tem que ser ativado. Isso abre a porta para outros aplicativos executarem código malicioso, como o registro de chamadas que tentam interceptar nomes de usuário e senhas. Além disso, um aplicativo malicioso poderia abrir outra página web que imita o fluxo de Link em uma tentativa de phishing.

Quando à procura de uma solução que é fácil de se integrar com os desenvolvedores, intuitiva para os usuários finais, e seguro, avaliamos várias opções:

  1. a construção de um nativo link de fluxo: Porque nativo Link fluxos iria também em outro aplicativo do processo, esclarecido que os desenvolvedores poderiam usar a reflexão para encontrar a nossa entrada EditTexts e registrar chamadas de retorno de uma forma semelhante ao Javascript em um modo de exibição da web.

  2. a criar uma aplicação de autenticação separada: Isso iria fornecer uma experiência nativa sandboxed e seria uma experiência ideal para os usuários finais; no entanto, muitos usuários não gostaria de baixar um aplicativo extra da Play Store. Isso significa que precisamos de uma solução de recurso para os usuários que se recusam a baixar o aplicativo.

  3. a abrir a ligação numa janela de navegação separada: esta seria uma solução segura e sandboxada. Quase todos os usuários têm um navegador instalado, mas a mudança de contexto de um aplicativo para um navegador introduziria um atraso notável, especialmente em dispositivos de baixo custo.

  4. usar as páginas personalizadas do cromo: Esta é a solução que escolhemos, pois não teve nenhum dos inconvenientes acima mencionados.

nossa escolha: Chrome Custom Tabs

Chrome custom tabs (CCT) é uma parte do navegador Chrome que se integra com o Android framework para permitir que aplicativos abram websites em um processo leve. O CCT abre mais rápido que um navegador e, se pré-carregado através de sua chamada de aquecimento, é potencialmente ainda mais rápido do que uma WebView. Enquanto ele ainda executa Javascript, ele está em seu próprio processo, o que impede aplicativos de executar código malicioso. Além disso, o CCT UI fornece uma barra de ação que mostra o URL da página que está sendo carregada, juntamente com um ícone de bloqueio de verificação SSL para páginas seguras. Isso garante aos usuários que a página correta está sendo mostrada.

alt

embora nem todos os usuários tenham Chrome instalado, a grande maioria tem. Para aqueles que não o fazem, nós estamos usando o método de fallback do navegador descrito acima (Opção 3); além de adicionar uma linha de código, nós obtemos o fallback gratuitamente a partir de CCT. Como já foi dito, o recurso do navegador não é a experiência ideal do usuário devido à sua latência, mas mantém o alto nível de segurança que o Plaid requer.

Como desenvolvemos o CCT solução, tivemos e abordou várias complicações:

  • a Obtenção de dados de eventos

  • Recuperando o resultado final

  • Controlar o CCT atividade & processo de

A obtenção de Dados de Evento

Quando um usuário navega entre as telas no Link, um redirecionamento ocorre e dados são fornecidos para os desenvolvedores nos parâmetros de URL.

alt

esta informação de redirecionamento é valiosa para os desenvolvedores, pois ajuda-os a entender o comportamento do Usuário. Com o CCT rodando em seu próprio processo e não fornecendo um retorno de redirecionamento, esta informação seria normalmente inacessível, o que tornaria nosso SDK seguro menos funcional para desenvolvedores do que suas implementações personalizadas de WebView.

para fornecer esta informação a partir da CCT, em vez disso Gravamos os eventos de redirecionamento no servidor em um datastore Redis. Quando o SDK Abre o Link, ele faz uma chamada de bootstrap para os nossos servidores, que fornecem um ID de canal por usuário escolhido por nós e uma chave secreta. O SDK então cria um objeto de trabalho app-scoped, que avalia o servidor usando um fluxo de intervalo RX. Em cada chamada de votação, fornecemos ao servidor o ID DO CANAL, a chave secreta e o UUID do último evento (ou nulo) para obter os últimos eventos.

1
2
3
4
5
6
7
8
9
10
11
12

Observáveis.Intervalo (Intervalo, TimeUnit.Segundos)
.subscribeOn (Schedulers.cálculo())
.observeOn(AndroidSchedulers.pão de centeio())
.flatMapSingle (makeNetworkCall)())
.assinar(
{
// tratar mensagens
},
{
// Lidar com erros
})

O Android quadro pode matar qualquer processo, incluindo a aplicação usando o Xadrez do SDK. Uma vez que o objeto do trabalhador Está ligado à aplicação, isso resultaria em que o trabalhador fosse parado. Se o usuário continuasse o fluxo, (com sucesso ou sem sucesso) o SDK faria uma chamada final para o canal e obter os eventos restantes. Os Eventos só seriam perdidos se o usuário abortasse o fluxo e a força matasse o aplicativo.

recuperando o resultado Final

semelhante à transmissão de dados de eventos para clientes, Link usa a URL para sinalizar que o usuário completou o fluxo. O URL relevante inclui os dados necessários, como a chave pública ou um código de erro.

uma vez que não podemos acessar a URL com CCT, armazenamos o resultado final em Redis com o mesmo ID de canal. Embora isso signifique que o nosso agente de votação saberia quando Link terminou, não haveria nenhuma garantia de que o trabalhador ainda estaria vivo. Mesmo que estivesse vivo, o usuário pode ter que esperar até a próxima votação para que o resultado seja entregue, o que pode ser um longo par de segundos.

para garantir que um resultado é entregue em tempo útil, usamos um link profundo para reabrir o SDK. O deep link é construído usando o app ID da aplicação, que deve ser associado com o segredo do cliente e whitelisted no painel de desenvolvimento. Isso, além do fato de que apenas um aplicativo em um dispositivo pode ter o mesmo ID app, garante que nenhum outro aplicativo interceptar o redirecionamento. O aplicativo Web Link, em seguida, constrói um URI de intenção, que é disparado no final do fluxo de Link.

1
2

intenção://redirect/#Intenção;regime=xadrez;pacote=$nome-do-pacote;end;

o Nosso SDK inclui uma intenção de filtro para lidar com a URI, para que o aplicativo re-abre e faz uma chamada directamente para o canal imediatamente.

1
2
3
4
5
6
7
8
9
10
11

<intenção-filtro>
<ação android:name="android.intencao.accao.Ver" />
<categoria android: nome = " android.intencao.categoria.Predefinição" />
<categoria android: nome = " android.intencao.categoria.Navegável" />
<data
Android: host = "redirect"
android:scheme="xadrez" />
</intenção-filtro>

Controlar CCT

CCT carece de interfaces para o aplicativo:

  • ouvir para quando o usuário fecha a atividade

  • detectar quando o usuário clicou no “Open Browser” opção

  • força para fechar

temos sucesso trabalhou em torno de todas essas deficiências.

em primeiro lugar, para ouvir quando o utilizador fecha a actividade, abrimos a CCT utilizando a actividadepartida e passamos-lhe um código de pedido. Se o usuário fechar CCT usando o X no canto superior esquerdo do botão de volta do sistema, o callback onActivityResult é despoletado com o código de solicitação que fornecemos e um código de resultado de atividade.Resultado anulado. A intenção de dados não inclui nenhuma informação, mas podemos fazer uma última chamada para o canal para obter os eventos restantes. Então passamos para o aplicativo cliente e devolvemos um objeto de LinkCancellation, sinalizando que Link foi fechado intencionalmente pelo Usuário.

em seguida, a potencial preocupação com a detecção quando o usuário clicou “Open in Browser” é que o usuário poderia então passar por todo o fluxo em uma aplicação separada, ou seja, o navegador. Isto não é um problema para nós, porque os sistemas de votação e de intenção continuam a funcionar da mesma forma e ainda podemos obter os dados necessários.

finalmente, quando o usuário completa o fluxo com sucesso e a intenção do resultado é disparada, o processo CCT permaneceria aberto e na lista de tarefas do Usuário. Este processo fantasma não só seria um desperdício, mas também poderia ser confuso para um usuário quando pressionam o botão “tarefas recentes” do sistema. Portanto, precisamos de uma maneira de forçar a CCT a fechar quando o fluxo estiver completo.

para fazer isso, nós usamos o padrão mostrado no OpenID Apauth para a Biblioteca Android. Em vez de lidar com o resultado na atividade que abre Link, colocamos o filtro de intenção em uma atividade separada. Esta segunda atividade lida com todos os redirecionamentos do aplicativo web, que incluem: completações bem sucedidas, erros que fecham o fluxo, oAuth ou redirecionamentos App-to-App, e erros gerais do sistema. A atividade, em seguida, passa os dados de volta para a atividade de abertura usando uma intenção com a intenção.FLAG_ACTIVITY_SINGLE_TOP and Intent.FLAG_ACTIVITY_CLEAR_TOP flags. Usados em conjunto, eles limpam tudo na pilha acima da atividade de abertura, incluindo a CCT.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

val intento = Intenção(atividade, LinkActivity::class.java)
quando (estado) {
é RedirectState.Cromecustomtabscomplete -> {
intenção.putExtra (LINK_CHROME_CUSTOM_TABS_COMPLETE_REDIRECT, true)
intent.putExtra(LINK_RESULT_CODE, state.resultCode)
intent.putExtra(LINK_RESULT, state.result)
}
is RedirectState.UserInitiatedChromeCustomTabsViewClose -> {
intent.putExtra(LINK_CHROME_CUSTOM_TABS_USER_CLOSE_REDIRECT, true)
}
is RedirectState.OAuth -> {
intent.putExtra(LINK_OAUTH_REDIRECT, true)
intent.putExtra(LINK_OAUTH_STATE_ID, state.oauthStateId)
}
is RedirectState.RedirectError ->
intent.putExtra(LINK_REDIRECT_ erro, true)
}
intenção.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP ou Intent.FLAG_ACTIVITY_CLEAR_TOP
voltar a intenção

alt

pensamentos Finais sobre CCT

, a fim de fornecer um seguro, em área restrita experiência não disponível no WebViews ou nativa fluxos de CCT é uma solução viável. É fácil de integrar com os desenvolvedores e oferece uma melhor experiência de usuário do que abrir janelas de navegador graças à sua natureza leve e velocidade.

a natureza de caixa de areia da CCT e a API limitada significam que não está sem as suas desvantagens. Ouvir redirecionamentos de URL, obter resultados finais e controlar o processo de CCT todos nos obrigaram a criar soluções criativas. Estas soluções dependiam de uma compreensão das características embutidas do Android, especialmente a estrutura de intenção.

os benefícios para desenvolvedores e consumidores valeram bem o esforço necessário e recomendamos o uso de CCT em outros aplicativos e SDKs para uma integração rápida e segura. Além disso, você pode usar as dicas fornecidas aqui para melhorar a experiência do Usuário (e desenvolvedor).Se você está interessado em resolver problemas únicos que serão usados por milhares de desenvolvedores e milhões de consumidores, visite nossa página de carreiras.

You might also like

Deixe uma resposta

O seu endereço de email não será publicado.