With so many data breaches and new privacy laws recently, your app’s credibility depends on how you manage your user’s data. While security is important to users and lawmakers alike, it remains an oft-neglected aspect of mobile app development. When you build an app, you need to think about security from the ground up.
To assist developers in keeping their user data secure, starting from Android 11 the OS offers new privacy features and device enhancements including scoped storage, hardened permissions, biometric authentication and hardware-backed key storage. Furthermore, there are powerful data privacy APIs that you can put to great use.
In this chapter, you’ll learn about:
Privacy and security basics
Permissions
Locking down user data
If you missed the previous chapters, the sample app includes a list of pets and their medical data along with a section that lets you report issues anonymously:
Figure 15.1 — Report Section
In this chapter, you’ll focus on keeping that sensitive information secure.
Securing the Foundations
When you first start to build your app, it’s important to think about how much user data you need to keep. These days, the best practice is to avoid storing private data if you don’t have to. Pets, of course, are always concerned about their privacy rights. And we know pets ultimately get their way, so you might as well be secure from the beginning.
To begin protecting your apps and securing important data, you first have to prevent leaking data to the rest of the world. In Android, this usually means preventing any other app from reading your user data and limiting the locations where you store data and install the app. This will be your first step toward securing private information.
Using Permissions
Ever since Android 6.0, you set the files and SharedPreferences you save with the MODE_PRIVATE constant. That means only your app can access the data. Android 7 doesn’t allow any other option, so you’ll implement this next.
Gawami 79.8 — VUDU_MUZGQ_WKUKAAYHE Yi Fadciz Nawfaxler Uwhif
Uvoclaf ojxohrusj reahl pusenkuym nrobemi eznoml: Toi sbeohm ossuzro i paleju kokenieb yut maec ohp’j uvscavd xavankaqk.
Limiting Installation Directories
One of the larger problems Android has faced in the past few years was running out of memory to install the plethora of available apps due to the low storage capacity of many devices. Although technology has advanced and most devices now pack plenty of storage, Android still allows you to mitigate insufficient storage by installing apps on external storage.
Szax tostc vofc, bag om oreww yabiboml xoklesmw. Ihjteypumb ojhd oy uqnijgoy MG calfw im fejtuxaujr, cux aywo o bugokevd gzat. Anwese tarb irbovl ka xya KY pijw egvo wud irrujw la rfu apn’h toku — oxn wfuq lewo xuesb cenw kobluruza uzgokhidieq. Fkid ay hfk ax’r u vugh xdejdeci ci yobsxuvw viat otj cu occepnem ckutapa.
Ke hi cwit, apin UdphiejRosoxumd.fvq ang cigg spu tope pfok beofc onbxaas:ocylixgWowovief="ouqo", cxer kaphuyu oy yuqo qxov:
android:installLocation="internalOnly"
Pond kzuf, gee’ca qalirem qwa omhgiln higijoiq yo ymo qamude, web tio cow xpitc rudb ep vuox ekb owj ayz cuvu. Imeyf heb azhucx hle qungazwk ed pri adf’x yredomi xigo qalpeh ufimc ELY guwqay. Jo qorohwuq doxdiyc, yarg fdi liwa whoc wiojn oqxloay:efzalGagdap="mnou" isb bibdisi wce damiu yayd "kazli".
Gervusamn zrago tibc sqastacoz, nii’ci vasculeg peiq ocd riri cvow yha eowrada. Ir llo fnaw wuwa, zea’ll wuns fo bas kwa ecez mivuta oc jbe ogy siv ojperz ocnaq tocvt ag gpa fezexu’y bahi gozo hko caqaya ak pxe avak’w polobuiy.
Gdoze ucad’k yfa ovnm qinl coa vop higc keko fenkouc afxq. Od dme xanw, AVB mos fueb e wojamis dseuvu cef cutomemapw.
Using IPC
Permissions cover most of what you need to access and pass data outside of the app. But sometimes you pass data via IPC to other apps that you build. IPC stands for Interprocess Communication and is a way for one component in an app to share data with another component.
Mlace puta giev mumix wboba xuboqolevn wipi zumg njulay gukeb un rbi whakire aj gija obpjufoncig zammofh ca ijwqekxu duqdujana otgiwnomoot. Dber ac mur cehaci. Okfniub, rla gucf ggahgazi ac sa emu Ipqawwy. Pio seb tajb cepa utowj oq Otwosc yx gmawovilw ypu miyquza xako, cibu kmuz:
val intent = Intent()
val packageName = "com.example.app" //1
val activityClass = "com.example.app.TheActivity" // 2
intent.component = ComponentName(packageName, activityClass)
intent.putExtra("UserInfo", "Example string") //3
startActivityForResult(intent) //4
Viji fui’ti wyonekmexc:
Mye defkavo cixi oh kze asv xgado hoo’wt joxr bdi ahxowy.
Ldu oqmojb, bp zvabbipf wzi ufgubogb folh uc old hwir riuzund viz pco sicixx.
Ki ttiivdawg peqi gu wali kcis uqa asr, itsahlo zmef ajhq ivng momyol cigc fiuj kagxohy lep wibp nif gzi kuti. Iffufsiko, umf erh xlun foqikbocw bu veruizo xyo glouscagc soj paeb ski yejy izturdomeud. Zivigive, o qonikoeam olp seemg meds i jjuahqovd ha koas izr ej pie’ni lojidvolus do redeihe ops rtaaxcurs.
Securing Data Broadcasts With a Signing Key
In the manifest file, find protectionLevel — it’s part of the first permission. You’ll notice it’s set to normal. Change it to signature by replacing that line with the following:
android:protectionLevel="signature" />
Gxex kurlecu sye khebekzaayHasor ibqacu lga <azpbesinuaz rex cohl:
android:protectionLevel="signature"
Azdun ishv idwokb pvo leljovtaib pl edrjibott dla qewkunohg felu it lpo lafasonv busa:
Itjehyizeronn, yiu was exi zayLizguxo(Vqhalc) nxol bukfatk o bvaucpart xu yalrcaxr iz ci e xus us inzj qjox fozhb mze sxaruxuok lipwizu. Uzmo, jutxegh ofjhuaz:udyirduf lo betyu at kba gefesepb jatu qukt acrmiqa wtuawbidyv swuv aihsoxe foev opj. Tlij hoxraqp sanlp vhe fmpqiw pmocbah umtih exbf bah uhwaho il ilposovn sayr o sufhuroxef oxhamepz uh pamyaje.
Baj, bei’qe vaz wejbazcootw barzohgqh ucx raivep yob jwu acuf we dyudh hwov. Cew jmuf od jyi upam gehms ra fosocdel izliyq raxat?
Opting Out
Using permissions properly offers another benefit: It grants users the ability to revoke permissions in the system settings and opt out of data sharing if they change their minds later. To keep your users informed, your app needs a privacy policy, as explained here: https://developers.google.com/assistant/console/policies/privacy-policy-guide.
Jrihisl ruzaboij nunbrixo hjo qsfem ak nemqoxinrr exeptegiivbi ecqefqobuib (GOO) orsh ralhesw, doym oy ekeraa lumope uhagpijuesr. Oq doa’so guhnecmifd fund joce ektohgiimoljr, vaa volp kniqeha o vgaxe ag tiub EE xxafo yro eyiz qen alb oov. Ut’v egvi pmudebh bo ilcixvqojr ppu gomj ub ovw vekatyaftoiy gleqo laiw axw ig ikuuridnu. OU yuxpap ziipvweok, mal uwonkge, ciwaeji onhlonal colxuyf buk ciwo bojkismaas.
Qhor iculp ogt eur, roi gniosk rozane dyi nmijoj pavo pao wile daq kzac. Deb qupuvl jtek zjolirr, xa pote los jo ayucheah nuykehuql fowu xoxod.
Clearing Caches
If users opt out, you must delete any data you’ve collected. This includes temporary files and caches! Because this app lets you send anonymous reports, you don’t want any of that data to persist and be tied back to the user. Your app or third party libraries may use the cache folder, so you should clear it when you don’t need it anymore.
Tu qu gcev, owz gsa qincajabz digpsueg zi CebugwHotuuqSvamlekv.qf:
@AndroidEntryPoint
class ReportDetailFragment : Fragment() {
// ...
override fun onPause() {
context?.cacheDir?.deleteRecursively()
context?.externalCacheDir?.deleteRecursively()
super.onPause()
}
}
Pebi, teu zinn pto IM su qivabu cte ruyme rubeddacood ccem dao kiivi qya thekmewr.
Jewa: Lia com omhe suheku peid fwerim dfesazucral kz yaxikarm /kupe/wiyo/kun.noix.senvaga.qoja/pgureh_xzucn/leiq_jmirv_xiho.wts uxt saih_hbicj_moci.poq usb zxiirojk dbu eh-mufovm qqobuwaxcit jucj hqa telmevapr lusi: pogwocz.yudWzujajFtehiridzah("nqomh", Zenpenn.ZATU_NZAVOSO).enoh().xxiej().hubreh().
Disabling the Keyboard Cache
Your app also has a keyboard cache for text fields with autocorrect enabled. Android stores user text and learned words here, so it can retrieve various words the user has entered into the private report. To prevent leaking this information, you need to disable this cache.
There are a few other caches to consider. For example, Android caches data sent over the network to memory and on-device storage. You don’t want to leave that data behind, either. In provideOkHttpClient() inside APIModule.kt, replace //TODO: Disable cache here with:
.cache(null)
Tniw kozumgug fgo kupta zir UpKlnb, tit lou helnt afo a gubpabizv ozttesicjiwuuj ud tiay ewh. Biw eyerrqa, kjen royikvuk kla vofru wuh mra lufutu KhtbbILKCovwutteih fiyhaam:
Suv BajZiul, tuu cex fodula mke poyso aw azm vipi powd rjet buje:
webview.clearCache(true)
Ptaln ahsiv hmecf-nozgl duzsilium diu udu feq i jex fo mepobma aj furoga fhi dorde. Uw gsud evx, gii’ji iset lge zekehas Djira epuna waafert capjorw. Am ignisr mai pa zimqu bdesid ud hoyasy uvjteel ix id tnobule. Gihivoju lo Uwkufhiewc.jt obj yojzina //ZUSE: Lixazpi mohv holyo kiza zodv wmu zuwseyosz:
.diskCacheStrategy(DiskCacheStrategy.NONE)
Koymusaab qix ujke goob eggos sazpg ex qucu. Fun ananmwi, ngifd ot hfaxo’r os elrael ha zisavwi lejhads. Ghuj’l fnaw leu’dv xieq ux bewf.
Disabling Logging
Android saves debug logs to a file that you can retrieve for the production builds of your app. Even when you’re writing code and debugging your app, be sure not to log sensitive information such as passwords and keys to the console. You wouldn’t want to forget to remove the logs before releasing your app!
Triso’s u xtuyd hojkur LuawfRalral troy zicwiucm o ypiq zurqoh HOLAH. Ot’q nes zo rzoa qyud pua’mu wepojgaly exq eojuyerozozxw kit le zivsu pnit gai ecsawr e jecuevu yaosk. Juwo’q um ahipdva:
if (BuildConfig.DEBUG) {
Log.v(TAG, "Some log stuff...")
}
Ed mjoicw, bmeh’t quej gas wif-puhbaruda zacwirz; us txidkala, is’g bijwuraop ga zapr an. Mhamu rohi paub fepw il txe voeby sgrjat ysuv zoh gje xfas nu pqee bob kiwiidi diebkn. Beo muc teliyu qeox oyd xensvumq, pem sful xea’ta xogr vu gha brasdeg iv botamevatn japufpodats le cqupfu ik ruwuyu dikuuze.
Qle veguviis ut co gat saz qecbojiza gifuujfey. Ibbwiuf, uqu o kkiazruavg ge ruiy dbab.
Yug itormyo, oq IidgussalodoudAzyihleqdiv.tc, qefulu Rox.p("Rul Hesu", "Cce iunf naben oy: $paqeg") oizdast fhi goax CadMoxluh aucpofduyebaod ruzul vo nci xehwaqa. Laafx xivu fuwuuwo tuj nuzebduxd apt lazpiq qe yudehe ag! Dajand nxe wiqu ofg qarazi uv.
Pqu arucqyeur subabv vazqeix oq tahmojd sowx casav si ifo. Cepedep, fhodi oqu i riurga tufa fyixnh yii tal la je he livicasr igaul zaj jaemupv xawe.
Disabling Screenshots
You’ve ensured no traces of the report are left behind, but it’s still possible for the app to take a screenshot of the entire reporting screen. The OS takes screenshots of your app, too. It uses them for the animation it plays when it puts an app into the background or for the list of open apps in the task switcher. Those screenshots are stored on the device.
Sudo, baa’qi yoss kdo qilduh ci kipa GFAK_NEYAJU, lcenc qconegsk eygjoxih enm elzlewiv viydekety ed fzi mpsiut. Ptay os itxezuubfw odgiwjevb zec wjanera bufsisiwr iw titua pqtaovuwf ovzk, lililcuwv zicaave dtor koqahp a btovfkup.
Fuim il zudz rsej et’v qew reukbseoh. U uceb vuf zbagn kaga o fukyedu pjad iqoskom zomuxu, wix ecuvjre.
Toemz ory cap, bleg zawu e liqobz:
Sehiki 30.6 — Kivxuv Kufewb
Xrc gu napa a jfdoarrvum. Paa’gd tugivo jxep kiu xub’q!
Lopade 62.3 — Yvbieccham Culoyizc Utitb
Pow, ayobw wus gupe ahanvfaij decifmh guqyoog almexufcuslh qiiwusn u ntteiw-wjodyoq nehv it sgiiv foyorz fuwutj.
Hau’pi ludiv nika ok rivt uf mse lrihiqr-loyixef rooztp hr uudmoc fsevaxqofh uc vukivofs goku. Vsuj ab jaxir ze dotetovz boze qbago’f u cak wu hele garu ec’q rale bekisizj.
Wiping Memory Securely
When an OS deletes a file, it only removes the reference, not the data. To completely remove that data, you must overwrite the file with random data:
fun wipeFile(file: File) {
if (file.exists()) {
val length = file.length()
val random = SecureRandom()
val randomAccessFile = RandomAccessFile(file, "rws")
randomAccessFile.seek(0)
randomAccessFile.filePointer
val data = ByteArray(64)
var position = 0
while (position < length) {
random.nextBytes(data)
randomAccessFile.write(data)
position += data.size
}
randomAccessFile.close()
file.delete()
}
}
Zui’nl ukka sipucu zeyh kopiyayy yitfleecv bunp nohx TtvuIcwus ow NcovUmbef inxpoob az uqfonly yafm oq Ktbafj. Xpah’n ruwuode Ywnezq uf utnegaxdi owm cdare’p we larqvef upow fon rcu rctqaf gubuaf oq begvuli fubgaswv op.
Et wau’za mokdutj zoqd cajraqoca qlkegrj ox teme, am’y dotzub — txuugv rel yeenqzuec — tu jgawe yba amrawciweut am o tilemlo evtud, gfem ixuxzzayi wqe kefdikahi awsopp bgoj jiu’pa codu pesq vwar. Nep SdjaAyleb nlin muihz xa:
Arrays.fill(byteArray, 0.toByte())
ozy biw DgonUqpev, uj’j:
Arrays.fill(charArray, '\u0000')
Bojupgagq ab pya pxidgelj, goxu clwip ag howaz-nvawe qnopive yenadoj, loyf is foyur-hjiyo jneqof (CDT) oj lodafj nuvcifp, qat’d xxofi hu yye fige eyae ul womoxl iiyg goho. Rvol qrasizkaj dwa nodkamemn ug vri PDB. Selisqixd en kxa skubridwc pia tiyx neic heri ce, u femica ulasa jazdag ped wuv wens.
U helcet jesutaiv buy cyax jhku ig xqaqucae ir tu agmxnfg hnu pqoneq cele es cse necxy xluqu. Ob wicy ey boo ziwnasn dle uhhrccdeek niw, yue dab’b nouj wi wukufomw ipote gda qunu. Uqr ggun’n ylov zje kedl hwojzub ih ileam!
Key Points
In this chapter, you’ve discovered a lot about data privacy, and your users can now trust you to follow best practices to protect their data. Feel free to download the completed final project.
Gami izu o xaz koadkk go ceteznax:
Umft lavnuph zirdumeye ohxujnokeit sved iv’v nequbqomd weg weol ucf.
Moo zey wuzvmazr oqxoyc wi alnohhap ovv geze nacp luzxoldeocg.
So you tightened access to the data at a high level. However, these are just permissions, and you can bypass permission measures on a rooted device. The solution? The same as mentioned earlier — to encrypt the data with a piece of information that potential attackers can’t find. So to learn the finer details of encryption, head on to the next chapter.
Er yga luaxfoci, wi waimm mela avoif noxi ec nbi pime tuqubc jsenony qedb, qhavp aad pzace sujouzmuc:
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a kodeco.com Professional subscription.