säkra WebViews med Chrome Custom Tabs

Plaid ger innovatörer i fintech-utrymmet genom att ge dem tillgång till finansiella data via ett enhetligt API. För att hjälpa slutanvändare att ansluta sina bankdata till fintech-appar utvecklade Plaid Link, en drop-in-modul som hanterar autentiseringsverifiering, multifaktorautentisering och felhantering för varje bank som stöds.

Android-utvecklare var tidigare tvungna att öppna Länkadresser i Webbvisningar. Varje app som ville använda Link krävde mycket utvecklaransträngning och utan standardisering var det säkert buggar i några av implementeringarna. För att förbättra utvecklarupplevelsen släppte vi nyligen en SDK som gör WebView lätt att integrera i alla appar med några rader kod.

dessutom är Webbvisningar inte helt säkra för slutanvändare som matar in känslig information i Länkflödet. För att göra vår SDK så säker som möjligt har vi implementerat den med Chrome custom tabs istället för Android WebViews. I den här artikeln förklarar vi varför vi har fattat det beslutet och hur vi har övervunnit de tekniska problemen vi stött på under vägen.

utvärdera våra alternativ

som en SDK körs vår kod inom andra utvecklares applikationer och i sin tur deras applikationsprocesser. För att kunna köra Link web app i en WebView måste Javascript vara aktiverat. Detta öppnar dörren för andra appar att köra skadlig kod, till exempel att registrera återuppringningar som försöker fånga användarnamn och lösenord. Dessutom kan en skadlig app öppna en annan webbsida som efterliknar Länkflödet i ett phishing-försök.

när vi letade efter en lösning som är enkel att integrera med för utvecklare, intuitiv för slutanvändare och säker utvärderade vi flera alternativ:

  1. bygga en native link flow: eftersom native Link flöden skulle också köras i en annan app process, kunniga utvecklare kan använda reflektion för att hitta våra input EditTexts och registrera återuppringningar på ett sätt som liknar Javascript i en WebView.

  2. skapa en separat autentiseringsapp: Detta skulle ge en inbyggd sandboxupplevelse och skulle vara en idealisk upplevelse för slutanvändare; men många användare vill inte ladda ner en extra app från Play Store. Detta innebär att vi skulle behöva en reservlösning för användare som vägrar att ladda ner appen.

  3. öppningslänk i ett separat webbläsarfönster: detta skulle vara en sandboxad, säker lösning. Nästan alla användare har en webbläsare installerad, men sammanhanget som byter från en app till en webbläsare skulle innebära en märkbar fördröjning, särskilt på low-end-enheter.

  4. använda Chrome anpassade flikar: Detta är den lösning vi valde, eftersom den inte hade någon av de nackdelar som nämns ovan.

vårt val: Chrome Custom Tabs

Chrome custom tabs (CCT) är en del av Chrome-webbläsaren som integreras med Android-ramverket för att tillåta appar att öppna webbplatser i en lätt process. CCT öppnas snabbare än en webbläsare och, om den är förinstallerad via sitt uppvärmningssamtal, är potentiellt ännu snabbare än en WebView. Medan det fortfarande kör Javascript är det i sin egen process, vilket förhindrar att appar kör skadlig kod. Dessutom tillhandahåller CCT-användargränssnittet en åtgärdsfält som visar webbadressen till sidan som laddas, tillsammans med en SSL-verifieringslåsikon för säkra sidor. Detta försäkrar användarna om att rätt sida visas.

alt

även om inte alla användare har Chrome installerat, gör de allra flesta det. För dem som inte gör det använder vi webbläsarens fallback-metod som beskrivs ovan (alternativ 3); annat än att lägga till en kodrad får vi fallbacken gratis från CCT. Som nämnts tidigare är webbläsarens fallback inte den perfekta användarupplevelsen på grund av dess latens, men den upprätthåller den höga säkerhetsnivån som Plaid kräver.

när vi utvecklade CCT-lösningen stötte vi på och behandlade flera komplikationer:

  • hämta händelsedata

  • hämtar det slutliga resultatet

  • kontrollera CCT-aktiviteten & – processen

hämta händelsedata

när en användare navigerar mellan skärmar i Link sker en omdirigering och data tillhandahålls till utvecklare i URL-parametrarna.

alt

denna omdirigeringsinformation är värdefull för utvecklare, eftersom det hjälper dem att förstå användarbeteende. Med CCT körs i sin egen process och inte ger en omdirigering återuppringning, denna information skulle normalt vara otillgänglig, vilket skulle göra vår säkra SDK mindre funktionell för utvecklare än deras egna WebView implementeringar.

för att tillhandahålla denna information från CCT registrerade vi istället omdirigeringshändelserna på servern i en Redis-datalagring. När SDK öppnar länk, det gör en bootstrap samtal till våra servrar, som ger en per användare kanal-ID som valts av oss och en hemlig nyckel. SDK skapar sedan ett App-scoped worker-objekt, som pollar servern med en RX-intervallström. På varje polling samtal ger vi servern med kanal-ID, hemlig nyckel och den senaste händelsens UUID (eller null) för att få de senaste händelserna.

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

observerbar.intervall (intervall, tidsenhet.Sekunder)
.subscribeOn (schemaläggare.beräkning())
.observeOn (Androidschemedulers.mainThread())
.flatMapSingle (makeNetworkCall())
.prenumerera(
{
// hantera meddelanden
},
{
// hantera fel
})

Android-ramverket kan döda alla processer, inklusive appen med Plaid ’ s SDK. Eftersom arbetsobjektet är knutet till ansökan skulle detta leda till att arbetaren stoppas. Om användaren fortsatte flödet (antingen framgångsrikt eller utan framgång) skulle SDK ringa ett sista samtal till kanalen och få de återstående händelserna. Händelser skulle bara gå förlorade om användaren avbröt flödet och kraften dödade appen.

hämta slutresultatet

i likhet med att skicka händelsedata till klienter använder Link webbadressen för att signalera att användaren har slutfört flödet. Den relevanta webbadressen innehåller nödvändiga data, till exempel den offentliga nyckeln eller en felkod.

eftersom vi inte kan komma åt webbadressen med CCT lagrade vi slutresultatet i Redis med samma kanal-ID. Även om detta innebär att vår omröstningsarbetare skulle veta när Link är klar, skulle det inte finnas någon garanti för att arbetaren fortfarande skulle leva. Även om det levde kan användaren behöva vänta tills nästa omröstning kräver att resultatet ska levereras, vilket kan vara ett par sekunder.

för att säkerställa att ett resultat levereras i rätt tid använder vi en djup länk för att öppna SDK igen. Den djupa länken är konstruerad med hjälp av programmets app-ID, som måste associeras med klienthemligheten och vitlistas på utvecklarens instrumentpanel. Detta, plus det faktum att endast en app på en enhet kan ha samma app-ID, säkerställer att inga andra appar avlyssnar omdirigeringen. Link web app bygger sedan en avsikt URI, som avfyras i slutet av Länkflödet.

1
2

uppsåt: / / omdirigera/ # uppsåt; schema=Pläd; paket = $Paketnamn; slut;

vår SDK innehåller ett avsiktsfilter för att hantera URI, så att applikationen öppnas igen och ringer direkt till kanalen omedelbart.

1
2
3
4
5
6
7
8
9
10
11

<intent-filter>
<åtgärd android: name= " android.avsikt.åtgärd.Visa" />
<kategori android: namn= " android.avsikt.kategori.Standard" />
<kategori android: namn= " android.avsikt.kategori.BROWSABLE" />
<data
android: host= "omdirigera"
android:schema= "plaid" />
</intent-filter>

kontrollera CCT

CCT saknar gränssnitt för appen till:

  • lyssna efter när användaren stänger aktiviteten

  • upptäck när användaren har klickat på alternativet ”Öppna i webbläsare

  • tvinga den att stänga

vi har framgångsrikt arbetat runt alla dessa brister.

först, för att lyssna efter när användaren stänger aktiviteten öppnar vi CCT med startActivityForResult och skickar den en förfrågningskod. Om användaren stänger CCT med hjälp av X i det övre vänstra hörnet av Systemback-knappen utlöses onactivityresult-återuppringningen med den förfrågningskod vi tillhandahöll och en resultatkod för aktivitet.RESULT_CANCELED. Dataintentionen innehåller ingen information, men vi kan ringa ett sista samtal till kanalen för att få de återstående händelserna. Vi skickar dem sedan till klientappen och returnerar ett LinkCancellation-objekt, vilket signalerar att länken stängdes avsiktligt av användaren.

därefter är det potentiella problemet med att upptäcka när användaren har klickat på ”Öppna i webbläsare” att användaren sedan kan gå igenom hela flödet i en separat applikation, nämligen webbläsaren. Detta är inte ett problem för oss, eftersom omröstnings-och avsiktssystemen fortsätter att fungera på samma sätt och vi kan fortfarande få de uppgifter som behövs.

slutligen, när användaren slutför flödet framgångsrikt och resultatintentet avfyras, skulle CCT-processen förbli öppen och i användarens uppgiftslista. Denna fantomprocess skulle inte bara vara slöseri, men kan också vara förvirrande för en användare när de trycker på systemknappen ”senaste uppgifter”. Därför behöver vi ett sätt att tvinga CCT att stänga när flödet är klart.

för att göra detta använde vi mönstret som visas i OpenId AppAuth för Android-biblioteket. Istället för att hantera resultatet i aktiviteten som öppnar länken placerar vi intent-filtret på en separat aktivitet. Denna andra aktivitet hanterar alla omdirigeringar från webbappen, som inkluderar: lyckade kompletteringar, fel som stänger flödet, OAuth eller App-till-App omdirigeringar, och allmänna systemfel. Aktiviteten skickar sedan data tillbaka till öppningsaktiviteten med hjälp av en avsikt med avsikten.FLAG_ACTIVITY_SINGLE_TOP och avsikt.FLAG_ACTIVITY_CLEAR_TOP flaggor. Används tillsammans rensar de allt på stapeln ovanför öppningsaktiviteten, inklusive CCT.

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

val intent = Intent (aktivitet, LinkActivity:: klass.java)
när (tillstånd) {
omdirigeras.ChromeCustomTabsComplete -> {
avsikt.putExtra (LINK_CHROME_CUSTOM_TABS_COMPLETE_REDIRECT, sant)
avsikt.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, sant)
}
avsikt.flaggor = avsikt.FLAG_ACTIVITY_SINGLE_TOP eller avsikt.FLAG_ACTIVITY_CLEAR_TOP
retur avsikt

alt

slutliga tankar om CCT

för att ge en säker, sandboxad upplevelse som inte är tillgänglig i Webbvisningar eller inbyggda flöden är CCT en hållbar lösning. Det är lätt att integrera med för utvecklare och ger en bättre användarupplevelse än att öppna webbläsarfönster tack vare sin lätta natur och hastighet.

CCT: s sandboxade natur och begränsade API betyder att det inte är utan dess nackdelar. Att lyssna på URL-omdirigeringar, få slutresultat och kontrollera CCT-processen krävde att vi skulle komma med kreativa lösningar. Dessa lösningar förlitade sig på en förståelse för Androids inbyggda funktioner, särskilt intent framework.

fördelarna för utvecklare och konsumenter var väl värda den nödvändiga ansträngningen och vi rekommenderar att du använder CCT i andra appar och SDK för en snabb och säker integration. Dessutom kan du använda tipsen här för att förbättra användarens (och utvecklarens) upplevelse.

om du är intresserad av att lösa unika problem som kommer att användas av tusentals utvecklare och miljontals konsumenter, besök vår karriärsida.

You might also like

Lämna ett svar

Din e-postadress kommer inte publiceras.