Sichern von WebViews mit Chrome Custom Tabs

Plaid ermöglicht Innovatoren im Fintech-Bereich den Zugriff auf Finanzdaten über eine einheitliche API. Um Endbenutzern zu helfen, ihre Bankdaten mit Fintech-Apps zu verbinden, entwickelte Plaid Link, ein Drop-In-Modul, das die Validierung von Anmeldeinformationen, die Multi-Faktor-Authentifizierung und die Fehlerbehandlung für jede unterstützte Bank übernimmt.

Android-Entwickler mussten zuvor Link-URLs in WebViews öffnen. Jede App, die Link verwenden wollte, erforderte viel Entwicklungsaufwand, und ohne Standardisierung musste es in einigen Implementierungen Fehler geben. Um die Entwicklererfahrung zu verbessern, haben wir kürzlich ein SDK veröffentlicht, mit dem WebView mit wenigen Codezeilen einfach in jede App integriert werden kann.

Darüber hinaus sind Webansichten für Endbenutzer, die vertrauliche Informationen in den Linkfluss eingeben, nicht vollständig sicher. Um unser SDK so sicher wie möglich zu machen, haben wir es mit benutzerdefinierten Chrome-Registerkarten anstelle von Android-Webansichten implementiert. In diesem Artikel erklären wir, warum wir diese Entscheidung getroffen haben und wie wir die technischen Probleme, auf die wir dabei gestoßen sind, überwunden haben.

Evaluierung unserer Optionen

Als SDK läuft unser Code in den Anwendungen anderer Entwickler und damit in deren Anwendungsprozessen. Um die Link Web App in einem WebView ausführen zu können, muss Javascript aktiviert sein. Dies öffnet die Tür für andere Apps, um bösartigen Code auszuführen, z. B. das Registrieren von Rückrufen, die versuchen, Benutzernamen und Kennwörter abzufangen. Darüber hinaus könnte eine bösartige App eine andere Webseite öffnen, die den Linkfluss in einem Phishing-Versuch nachahmt.

Bei der Suche nach einer Lösung, die für Entwickler einfach zu integrieren, für Endbenutzer intuitiv und sicher ist, haben wir verschiedene Optionen geprüft:

  1. erstellen eines nativen Link-Flows: Da native Link-Flows auch im Prozess einer anderen App ausgeführt werden, können versierte Entwickler Reflection verwenden, um unsere Eingabe-EditTexts zu finden und Rückrufe ähnlich wie Javascript in einer Webansicht zu registrieren.

  2. erstellen einer separaten Authenticator-App: Dies würde eine native Sandbox-Erfahrung bieten und wäre eine ideale Erfahrung für Endbenutzer; Viele Benutzer möchten jedoch keine zusätzliche App aus dem Play Store herunterladen. Dies bedeutet, dass wir eine Fallback-Lösung für Benutzer benötigen, die sich weigern, die App herunterzuladen.

  3. link in einem separaten Browserfenster öffnen: Dies wäre eine sichere Sandbox-Lösung. Fast alle Benutzer haben einen Browser installiert, aber der Kontextwechsel von einer App zu einem Browser würde eine spürbare Verzögerung verursachen, insbesondere auf Low-End-Geräten.

  4. verwenden von benutzerdefinierten Chrome-Registerkarten: Dies ist die Lösung, die wir gewählt haben, da sie keinen der oben genannten Nachteile hatte.

Unsere Wahl: Chrome Custom Tabs

Chrome Custom Tabs (CCT) ist ein Teil des Chrome-Browsers, der in das Android-Framework integriert ist, damit Apps Websites in einem einfachen Prozess öffnen können. CCT öffnet sich schneller als ein Browser und ist, wenn es über seinen Aufwärmaufruf vorinstalliert ist, möglicherweise sogar schneller als ein WebView. Während es noch Javascript ausführt, befindet es sich in einem eigenen Prozess, der verhindert, dass Apps schädlichen Code ausführen. Darüber hinaus bietet die CCT-Benutzeroberfläche eine Aktionsleiste, die die URL der geladenen Seite sowie ein SSL-Verifizierungssperrsymbol für sichere Seiten anzeigt. Dies versichert den Benutzern, dass die richtige Seite angezeigt wird.

alt

Während nicht alle Benutzer Chrome installiert haben, die überwiegende Mehrheit tun. Für diejenigen, die dies nicht tun, verwenden wir die oben beschriebene Browser-Fallback-Methode (Option 3); Abgesehen vom Hinzufügen einer Codezeile erhalten wir den Fallback kostenlos von CCT. Wie bereits erwähnt, ist der Browser-Fallback aufgrund seiner Latenz nicht die ideale Benutzererfahrung, behält jedoch das hohe Sicherheitsniveau bei, das Plaid erfordert.

Als wir die CCT-Lösung entwickelten, stießen wir auf mehrere Komplikationen und gingen diese an:

  • Abrufen von Ereignisdaten

  • Abrufen des Endergebnisses

  • Steuern des CCT activity & -Prozesses

Abrufen von Ereignisdaten

Wenn ein Benutzer zwischen Bildschirmen in Link navigiert, erfolgt eine Umleitung, und den Entwicklern werden Daten in den URL-Parametern bereitgestellt.

alt

Diese Umleitungsinformationen sind für Entwickler wertvoll, da sie ihnen helfen, das Benutzerverhalten zu verstehen. Da CCT in einem eigenen Prozess ausgeführt wird und keinen Umleitungsrückruf bereitstellt, ist auf diese Informationen normalerweise nicht zugegriffen werden, wodurch unser sicheres SDK für Entwickler weniger funktionsfähig wäre als ihre benutzerdefinierten WebView-Implementierungen.

Um diese Informationen von CCT bereitzustellen, haben wir stattdessen die Umleitungsereignisse auf dem Server in einem Redis-Datenspeicher aufgezeichnet. Wenn das SDK den Link öffnet, führt es einen Bootstrap-Aufruf an unsere Server durch, die eine von uns ausgewählte Kanal-ID pro Benutzer und einen geheimen Schlüssel bereitstellen. Das SDK erstellt dann ein Worker-Objekt mit Anwendungsbereich, das den Server mithilfe eines RX-Intervallstreams abfragt. Bei jedem Abfrageaufruf stellen wir dem Server die Kanal-ID, den geheimen Schlüssel und die UUID des letzten Ereignisses (oder null) zur Verfügung, um die neuesten Ereignisse abzurufen.

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

Beobachtbar.intervall(Intervall, Zeiteinheit.SEKUNDEN)
.subscribeOn(Planer.berechnung())
.observeOn(AndroidSchedulers.Hauptgewinde())
.flatMapSingle(makeNetworkCall())
.abonnieren(
{
// Nachrichten verarbeiten
},
{
// Fehler behandeln
})

Das Android-Framework kann jeden Prozess beenden, einschließlich der App, die das SDK von Plaid verwendet. Da das Worker-Objekt an die Anwendung gebunden ist, würde dies dazu führen, dass der Worker gestoppt wird. Wenn der Benutzer den Fluss fortsetzte (entweder erfolgreich oder erfolglos), würde das SDK einen letzten Aufruf an den Kanal tätigen und die verbleibenden Ereignisse abrufen. Ereignisse gehen nur verloren, wenn der Benutzer den Fluss abbricht und die App erzwingt.

Abrufen des Endergebnisses

Ähnlich wie beim Übergeben von Ereignisdaten an Clients verwendet Link die URL, um zu signalisieren, dass der Benutzer den Ablauf abgeschlossen hat. Die entsprechende URL enthält notwendige Daten wie den öffentlichen Schlüssel oder einen Fehlercode.

Da wir mit CCT nicht auf die URL zugreifen können, haben wir das Endergebnis in Redis mit derselben Kanal-ID gespeichert. Dies bedeutet zwar, dass unser Polling-Mitarbeiter weiß, wann Link fertig ist, Es gibt jedoch keine Garantie dafür, dass der Mitarbeiter noch am Leben ist. Selbst wenn es lebendig wäre, muss der Benutzer möglicherweise bis zum nächsten Abfrageaufruf warten, bis das Ergebnis zugestellt wird, was einige Sekunden dauern kann.

Um sicherzustellen, dass ein Ergebnis zeitnah geliefert wird, verwenden wir einen Deep Link, um das SDK erneut zu öffnen. Der Deep Link wird mithilfe der App-ID der Anwendung erstellt, die mit dem Client-Secret verknüpft und im Entwickler-Dashboard auf die Whitelist gesetzt werden muss. Dies und die Tatsache, dass nur eine App auf einem Gerät dieselbe App-ID haben kann, stellen sicher, dass keine anderen Apps die Umleitung abfangen. Die Link-Web-App erstellt dann einen Intent-URI, der am Ende des Linkflusses ausgelöst wird.

1
2

intent://redirect /#Intent; Schema = plaid; Paket = $ PackageName; Ende;

Unser SDK enthält einen Intent-Filter, um den URI zu verarbeiten, sodass die Anwendung erneut geöffnet wird und sofort einen Anruf direkt an den Kanal tätigt.

1
2
3
4
5
6
7
8
9
10
11

< intent-Filter>
< aktion android: name="android.Absicht.Aktion.ANSICHT" />
< kategorie android:name="android.Absicht.Zimmerkategorie.STANDARD" />
< kategorie android:name="android.Absicht.Zimmerkategorie.DURCHSUCHBAR" />
< daten
android: host="umleiten"
android:schema ="plaid" />
</ intent-Filter>

Controlling CCT

CCT fehlt Schnittstellen für die App zu:

  • warten Sie, wenn der Benutzer die Aktivität schließt

  • erkennen, wann der Benutzer auf die Option „Im Browser öffnen“ geklickt hat

  • zwingen Sie es zu schließen

Wir haben alle diese Mängel erfolgreich behoben.

Um zu warten, wann der Benutzer die Aktivität schließt, öffnen wir CCT mit startActivityForResult und übergeben ihm einen Anforderungscode. Wenn der Benutzer CCT mit dem X in der oberen linken Ecke der Schaltfläche System zurück schließt, wird der onActivityResult-Rückruf mit dem von uns angegebenen Anforderungscode und einem Ergebniscode der Aktivität ausgelöst.RESULT_CANCELED. Die Datenabsicht enthält keine Informationen, aber wir können den Kanal endgültig aufrufen, um die verbleibenden Ereignisse abzurufen. Wir übergeben sie dann an die Client-App und geben ein LinkCancellation-Objekt zurück, das signalisiert, dass der Link vom Benutzer absichtlich geschlossen wurde.

Als nächstes besteht das potenzielle Problem beim Erkennen, wann der Benutzer auf „Im Browser öffnen“ geklickt hat, darin, dass der Benutzer dann den gesamten Ablauf in einer separaten Anwendung, nämlich dem Browser, durchlaufen kann. Dies ist für uns kein Problem, da die Polling- und Intent-Systeme weiterhin auf die gleiche Weise funktionieren und wir weiterhin die benötigten Daten erhalten können.

Wenn der Benutzer den Ablauf erfolgreich abschließt und die Ergebnisabsicht ausgelöst wird, bleibt der CCT-Prozess geöffnet und in der Aufgabenliste des Benutzers. Dieser Phantomprozess wäre nicht nur verschwenderisch, sondern könnte auch für einen Benutzer verwirrend sein, wenn er die Systemschaltfläche „Letzte Aufgaben“ drückt. Daher brauchen wir eine Möglichkeit, CCT zum Schließen zu zwingen, wenn der Fluss abgeschlossen ist.

Um dies zu tun, haben wir das Muster in der OpenID AppAuth für Android-Bibliothek gezeigt. Anstatt das Ergebnis in der Aktivität zu verarbeiten, die den Link öffnet, platzieren wir den Absichtsfilter in einer separaten Aktivität. Diese zweite Aktivität behandelt alle Weiterleitungen von der Web-App, darunter: erfolgreiche Abschlüsse, Fehler, die den Ablauf schließen, OAuth- oder App-zu-App-Weiterleitungen und allgemeine Systemfehler. Die Aktivität übergibt die Daten dann mithilfe einer Absicht mit der Absicht an die Eröffnungsaktivität zurück.FLAG_ACTIVITY_SINGLE_TOP und Intent.FLAG_ACTIVITY_CLEAR_TOP Flags. Zusammen löschen sie alles auf dem Stapel über der Eröffnungsaktivität, einschließlich CCT.

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

val intent = Absicht (Aktivität, LinkActivity:: Klasse.java)
when (state) {
ist RedirectState.ChromeCustomTabsComplete -> {
absicht.putExtra(LINK_CHROME_CUSTOM_TABS_COMPLETE_REDIRECT, true)
Absicht.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_ERROR, wahr)
}
absicht.flags = Absicht.FLAG_ACTIVITY_SINGLE_TOP oder Absicht.FLAG_ACTIVITY_CLEAR_TOP
Absicht zurückgeben

alt

Abschließende Gedanken zu CCT

Um eine sichere Sandbox-Erfahrung zu bieten, die in WebViews oder nativen Flows nicht verfügbar ist, ist CCT eine praktikable Lösung. Es ist für Entwickler einfach zu integrieren und bietet dank seiner Leichtigkeit und Geschwindigkeit eine bessere Benutzererfahrung als das Öffnen von Browserfenstern.

Die Sandbox-Natur von CCT und die eingeschränkte API bedeuten, dass es nicht ohne Nachteile ist. Das Abhören von URL-Weiterleitungen, das Erzielen von Endergebnissen und die Steuerung des CCT-Prozesses erforderten kreative Lösungen. Diese Lösungen beruhten auf einem Verständnis der integrierten Funktionen von Android, insbesondere des Intent-Frameworks.

Die Vorteile für Entwickler und Verbraucher haben sich gelohnt und wir empfehlen die Verwendung von CCT in anderen Apps und SDKs für eine schnelle und sichere Integration. Darüber hinaus können Sie die hier bereitgestellten Tipps verwenden, um die Benutzererfahrung (und Entwickler) zu verbessern.

Wenn Sie daran interessiert sind, einzigartige Probleme zu lösen, die von Tausenden von Entwicklern und Millionen von Verbrauchern verwendet werden, besuchen Sie unsere Karriereseite.

You might also like

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.