Preskoči na sadržaj

Čitanje NFC čipa u pasošu iz React Nativea

Godine 2020. za to nije postojala upotrebljiva biblioteka. Nativni modul u Javi, ista logika prenesena u Swift i jedan zajednički interfejs kroz Turbo Module.

5 min čitanja6 sekcija

Godine 2020. radio sam na verifikaciji identiteta na daljinu za njemačku finansijsku instituciju. Korisnici su pred kamerom prolazili kroz šest nasumično poredanih koraka, a model računarskog vida procjenjivao je da li dokument koji drže izgleda vjerodostojno. To je radilo, ali je i dalje bilo zaključivanje: model je vjerovao da gleda pravi pasoš.

Čip daje drugu vrstu odgovora. Predaje podatke koje je potpisala država koja je izdala dokument. Njegovo čitanje pomjera provjeru od procjene ka dokazu, i zato se isplatilo uraditi ga iako nije postojalo ništa čime bi se to uradilo.

01

Zašto ne biblioteka

Godine 2020. nijedan paket nije čitao NFC čip dokumenta iz React Nativea u stanju koje biste stavili pred banku. Apple je čitanje čipa otvorio aplikacijama trećih strana tek godinu ranije. Ono što je postojalo bilo je uglavnom nativno, uglavnom za Android i uglavnom neodržavano. Zato sam protokol implementirao nativno i napravio ga dostupnim iz JavaScript sloja.

02

Šta protokol traži od vas

Prvo iznenađenje za većinu ljudi je da pasoš ne možete jednostavno prisloniti. Čip neće odgovoriti dok ne dokažete da fizički držite dokument, a to morate dokazati onim što je odštampano na stranici.

snippet.txt
Tekst · 10 linija
MRZ, s odštampane stranice └─ broj dokumenta + datum rođenja + datum isteka, svaki s kontrolnom cifrom     └─ BAC / PACE: sesijski ključevi izvedeni upravo iz toga         └─ sigurni kanal: svaka komanda šifrovana i MAC-ovana, brojač sekvence             └─ DG1   podaci mašinski čitljive zone                DG2   fotografija lica                SOD   potpisani heševi svake grupe podataka                 └─ pasivna autentifikacija:                    provjeri potpis države izdavaoca,                    pa ponovo heširaj svaku grupu i uporedi

BAC izvodi sesijske ključeve iz mašinski čitljive zone, pa je redoslijed čitanja zadan: prvo uzmite MRZ, s kamere ili otkucan, pa onda razgovarajte s čipom. PACE je noviji mehanizam s istom idejom i mnogo boljim dogovorom o ključu, otporan na offline napad koji BAC-ov ključ niske entropije dozvoljava. Koji ćete dobiti zavisi od dokumenta, pa prava implementacija podržava oba i pregovara.

Poslije toga sve ide preko sigurnog kanala s brojačem sekvence, što ima praktičnu posljedicu: ako telefon usred čitanja izgubi polje, sesija je gotova. Ne nastavlja se, nego se kreće ispočetka, a interfejs to mora reći tako da se korisnik ne osjeti optuženim.

Pasivna autentifikacija je korak koji je bitan, i korak koji se najlakše preskoči. Sigurnosni objekat dokumenta sadrži heš svake grupe podataka, potpisan od države koja je izdala pasoš. Provjera tog potpisa i ponovno heširanje onoga što ste pročitali razlika je između čitanja čipa i vjerovanja čipu. Ako je preskočite, imate zgodnu prečicu za unos podataka koju falsifikator može popuniti.

03

Jedan interfejs, dvije nativne implementacije

Protokol sam razradio i napisao u Javi za Android. Verzija za iOS je ista logika prenesena u Swift, s istim ponašanjem, a ne projektovana po drugi put. React Native je vidio jedan zajednički interfejs kroz Turbo Module, s dvije nativne implementacije iza njega.

Prenošenje umjesto ponovnog pisanja bilo je namjerno. Dvije nezavisne implementacije ICAO čitača razići će se na rubnim slučajevima, kao što su neuobičajena grupa podataka ili konvencija kontrolne cifre. Tada isti pasoš prolazi na jednom telefonu, a pada na drugom. Na takav zahtjev podršci niko ne može odgovoriti, a korisnik zaključuje da je vaša aplikacija pokvarena, i u pravu je.

Na JavaScript strani ništa od ovoga nije vidljivo. Jedan poziv, tipiziran rezultat, tipizirane greške:

oblik toga, u današnjim terminima API-ja
TypeScript · 11 linija
// oblik toga, u današnjim terminima API-jaexport interface Spec extends TurboModule {  readDocument(key: {    documentNumber: string    dateOfBirth: string   // YYMMDD, iz MRZ-a    dateOfExpiry: string  }): Promise<{    mrz: string           // DG1    portrait: string      // DG2, base64  }>}

Podatke pročitane s čipa dekodirao je eksterni servis, a moj dio završavao se na čitanju. Tu granicu vrijedi imenovati: posao modula završavao je na „evo šta je čip rekao“. Provjera potpisa nije bila dio toga.

04

Turbo Moduli 2020. godine

Tada su bili eksperimentalni dio nove arhitekture React Nativea: registrovali su se ručno, bili su oskudno dokumentovani i godinama daleko od stabilnog izdanja. Izabrati ih za proizvod koji ide u finansijsku instituciju bilo je rano usvajanje u doslovnom smislu.

Odluku je činilo odbranjivom to što je alternativa za ovaj posao bila gora. Čitanje čipa je razgovor sa stanjem, s fizičkim predmetom u nečijoj ruci. Osjetljivo je na kašnjenje i pada na desetak načina koji se mogu razlikovati. Tipiziran interfejs generisan iz jedne deklaracije, umjesto labavo tipiziranih poruka preko starog mosta, pravi je oblik za to, čak i kad su alati oko njega nezreli.

05

Dijelovi na koje vas niko ne upozori

Antena nije tamo gdje korisnik misli. Njen položaj se razlikuje od modela do modela telefona, a čip pasoša je u koricama ili na stranici s podacima, zavisno od dokumenta. Ljudi drže pasoš iznad ekrana, jer su tamo uputstva. Ilustracija mora prikazati poleđinu telefona.

Čitanje traje sekunde, ne milisekunde. To je dovoljno dugo da se ljudi pomjere, a pomjeranje završava sesiju. Interfejs mora zadržati pažnju kroz čekanje i mora razlikovati „držite i dalje“ od „krenite ispočetka“.

Taksonomija grešaka jeste funkcionalnost. Pogrešan MRZ ključ, čip van dometa, nepodržan tip dokumenta, neuspjela provjera potpisa: četiri različita problema, četiri različite stvari koje osoba treba uraditi sljedeće, a samo je jedna od njih njena greška. Ako ih sažmete u „Dokument nije moguće pročitati“, rješiv trenutak pretvarate u napuštenu prijavu.

06

Šta bih danas uradio drugačije

Većinu toga. Danas postoje održavane biblioteke, nova arhitektura je stabilna, a čitanje čipa na iOS-u je obična stvar. Kad bi isti zadatak stigao sutra, uzeo bih ono što postoji i vrijeme potrošio na dijelove iznad, koji nisu postali lakši.

Dvije implementacije bih i testirao drugačije. Kod iz Jave sam ručno prenio u Swift i taj prenos provjerio testiranjem. Trebao sam napraviti zajednički skup testnih vektora za protokol, poznate ulaze s očekivanim izlazima, i pustiti obje implementacije kroz njega. Provjeriti da se dvije implementacije ponašaju isto nije isto što i provjeriti da su ispravne.

Jedina odluka koju bih ponovio jeste da se protokol napiše jednom i prenese. Kako god izgledao sloj platforme, dva nezavisna čitanja istog standarda prije ili kasnije će se razići oko istog pasoša, a saznat ćete to od osobe koja je već pokušala tri puta.

Kako je nastao ovaj tekstVerifikacija identiteta na daljinu za njemačku finansijsku instituciju, gdje je čitanje čipa pasoša dodato povrh provjere od šest koraka pred kamerom.Pročitajte više o projektu →Povezana uslugaVerifikacija identiteta i KYCPogledajte uslugu →Sljedeći tekstTehnički due diligence: prvo pročitajte račun, pa kodPročitajte →

Blog

Ako radite na nečemu sličnom, javite nam se s detaljima.

Prvi poziv traje 30 minuta i ni na šta vas ne obavezuje.

Opišite nam svoj projekatcontact@microtech.consulting