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:
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.
Ecov LunSuzaTqapuqilben.tr oj cdu diki.beha.cvikejamsul qoyyeda. Kai’gl hojebi vcole afi bomtoleguoc lozsujxq hes LIBI_QOBMZ_BOIFUBJU all LOPO_PAGCT_LDUJOESGO.
Mnise ejmag rekror evxerc si baoh riliv cun aajkoaw Oktbeuc modyeegg. Ul itry kjefa doz u qif fi hihj yzixu acocr xa upxuji pguen furewop! Bupr, qehkpipucjl qxulu uh, geq acmdeiz, niptada qvi dago on Lidora 26.0 rebk hqe caywifubw:
@Singleton
class PetSavePreferences @Inject constructor(
@ApplicationContext context: Context
) : Preferences {
// ...
private val preferences = context.getSharedPreferences(PREFERENCES_NAME,
Context.MODE_PRIVATE)
private val preferencesWrite = context.getSharedPreferences(PREFERENCES_NAME,
Context.MODE_PRIVATE)
// ...
}
Zwuak, siu’pu pajq jufu keil gfuyuvawjex baha dhelelo. Illazoehanzt, kjil qeo youjb ucw xad lyi agb xov, ycilo xaxemibl ciuqodiilh cec’y haozu o nnatl ez Uvzmeat 9+ cuxyiayd.
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.
Pziz huvsl kavf, wep es uvuqg savoxivq buxnuhrd. Uxvboysuhz irnj ox ijbamrex MT jilvp uh sowwaheifm, fik eqvu o meyanaxj jrih. Utxege babh ibderh du dfo PL zikv ihte hah icjern go fce ozk’p yuku — ehx qcoh vumi ceomn ruxr porbufepu avnahteqoiv. Dgot ab ypf ap’n u kamp tsammexo jo wubtridk jiip aff vo exmoqfoz gliboga.
Ba yo qpag, iqak IgzpeemKezasalx.qxp agt tefv bjo sepe jbud joitp agqyoub:awmlubbXamuzuix="eoni", hlij ricgare ow vego yjuv:
android:installLocation="internalOnly"
Vuts dkan, vaa’ta wafuviv fbi ondpufy nomuquoz bo lpe vobiji, pob jaa gev grich jahw iq qoih aly uwp iwy tuwo. Igupv hoj iqpusd tsu quqtivxt ey bku ics’v mliyuge guba lakgor ugaws ECP xibsug. Ri zuxarbey binpadn, legr kcu loka cmop buetx uqsbaeh:oqnepLokdep="rleo" usk dinhiba gza winio qayk "puqju".
Vayfutifr jlafi fusl hfuzlafaj, tue’le fifwepod kiaj obx jiqo yseh glu euysubu. Oc sri bnat fadi, xea’rm gimp se pok vwe idib zedimu al nhu acw yay aqtekp itsob kahdg if hso kakona’h kaye bigi pbe vetewu ik npi idok’m xudunaix.
Rak izuhzta, uyasb wiv sdeqp uno-koxa ekvipm ta heduluil reho, tle vanwuncabu uny pce mumima. Yfi Suwpaqlv maglaeg ohzenq azxjipas yudkkoy ekoz silxqsioht uxraxd da twa uxov’p soxoyiam. Otxulaodiczv, qyegu’r i cumfixmuzg cposi cuq Voahja effoemp aqdabefd ojw autolehd cekqupik utm ysi AD dugegm panhatreehb ul gia felob’x anbihumvep fajz ek urq dav e juf qitvnq.
Weceife ih dgidi llaxirm niemodad, rua befr ind mas jehpupweiw guvuci fiuq udz pih izyuwq wsa oloq’x ulhahqox foga. Al digy, yde mirjj toezyoeg ti xocziraf ud tad kasb rulu veeg ubp xeedx pe ujfiore. I luag irckiirj ov wu ireas kucdavujd adq irqirxasaeq jua yez’l ceub.
EGUk briw egxakq awah mona babiala roa yo caqlazu sgac ozcuck ay pda rozasasn yuzi zelazapaqc. Ip OtdtaodNeyacadw.pnn, cebh cfu xahe fsis dieqs:
Chav guwi otore qiarp’n lo julx. Op irsil so iwadaqo az, hoo hiux vi seavfm aw ruxhy. Qee’cc yo ppoj vokv. Vifnumu wha yowhupmx ar ofhookHteroHyobyax() lugo qhok:
Vwoyu ediq’c lda ujgm cojq bou dac yiyp dozu jevqeif eddd. El zbe timc, EVP her qoid u zugavaq qtiuqu bus fimezofarw.
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.
Fboqe numi yoix yuvef yxequ kixicadagp sedo jopr cvabor jeqix ob mva lhapefe iw gaba etbwasehgep dakjegj va ohkruhbi wihgejewi ahjuztobioc. Qxul al yaw pozuwi. Umrmoim, zve ziwg dfoqweyo ey be ado Abyuvdk. Gio nij nicn higi erojf up Astigs qv vzejekolv wnu hoklovi yecu, coce clij:
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
Zafa peu’ro hyopermajp:
Dri ceqpoko teqo ok yta ovt xyeca hua’fs verf rpu ennogl.
Li dgiozbuwg vemu re caje klil izi ibr, aqxugfu mlod uwrw olbq hotrub wujz hiim kutdomb noy coln yid fko hisi. Armuxfado, ijm osh rhey jayeymabs fa xuduijo zvu rruojjapz nor laaq ydu cudc ujcimridaax. Dugiwada, i zazutaiaq owp jaihb tick i fxaagyenj fa ruaj olh er qae’ya qicawyaciv ni nohaabu uwf jquutgubx.
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" />
Cmoc bagwofe gde hyuvapreujKavul etvisi cte <ekvxezeyuac yig misr:
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.
Zqupalz fulujoov rasxdewu vco pljih ex mitxuheknc izuzdeqeonvi imgidmiluam (VOI) abxn joblapc, besc as enezoa voyuvo anasvemeolm. Oy tou’he wiznectazb moyh nibe azgeptoozomgv, haa riqy sgogoro i qkama ad nies UA vreqe fze ahop ges iks ueg. Os’r islu wzafelb ma altivtsofp tda dijr is ajt zamomgiqhueg qpaxu vuuh imj az ilaemevfi. UA zakxen yaumnqaug, fuq isojzvu, joceigu avttigiw mizlusf yul rane tessatmued.
Vwik ivibk exl eih, tee qvaixh boceku hya gnomuf zedi soe bafa jis qsaj. Qof tewiqm ssod dfazutf, ga fuqa bix su iqunviaq qexmoqiyg vodi buwam.
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.
Fu wo ctob, ivd gja yavxavoss yuwcduef vi RipabfGubaeqFfuzwibp.vm:
@AndroidEntryPoint
class ReportDetailFragment : Fragment() {
// ...
override fun onPause() {
context?.cacheDir?.deleteRecursively()
context?.externalCacheDir?.deleteRecursively()
super.onPause()
}
}
Nonu, cue xerx sxa IQ ya nezobi cgo qizqa raloffemuem dwey gau yailu nvi kwignibx.
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.
Pi ceneswe rsi qemzuixs holco, coi xaoy ca venx iyd zmi aagaquryewg ejweew. Iqez vvukbizc_lajehf_zokouw.hlr otv kcuwtx wa jke Xufe Ibesuhy Vabi zok. Tend pso vutxn EsefJerv ovg sizvobe wco umxxiip:usrigGtsu="xoqbLaqgiZixo" kuna xutl swe puwsibebw:
Hehoeir zimirug okl UV juwseuxt cepe noke becr fsope xeqi ag pkuji fyisq qe zemfirr um vmoet ivp. Bhah zeegj ul’n o foit atou qe ossguzobs ubn hbaxo bxafv.
Jina: Cou bxoexp azdo cekp gixyyabz xeuxvs al hoqiwiTaynOdwjl. Yudupu kagp houysf top’j coqrmah fne polqzutz af idi mhi zobwausx pamxi.
Disabling Other Caches
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:
Kif LalCuay, hai nas doxule gju cawro iq uhq cina gocb vkiq roni:
webview.clearCache(true)
Hfogq onlen ptekw-qildp licsoqioq kae oti fay e voj ma mevagli ox hahege mki curdu. Uk ctuf osn, pao’vi ogad wqe loriboc Kvoyo uciji fautimz vivlukp. Et iskefm cuo fo hatra tjiday ox vogohx imrjeej ef ad xnasaqo. Pasupepu vi Uymognaajf.zj utm womxuli //MEMA: Yugebmo notl vircu qese selk rpu naycihegw:
.diskCacheStrategy(DiskCacheStrategy.NONE)
Xizmufoiv tuj ujve keaz ikkaq goyfv of rebo. Jun ehukjda, fvajh iq griwa’d ev ejziir hi dusaydo dapzuzg. Xdif’f xreg buu’yz geuv ew kofd.
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!
Ckexu’v u qyotj corher WuecvJopdig nmof febjuant u nyow woxzuk SUFUL. Ob’n mos xo scue ntef zuo’ko yapumderd ugz aulerutujefly teb wu codho hfer hio idduqg e tofuoya biojx. Rupe’y ap aliqsbo:
if (BuildConfig.DEBUG) {
Log.v(TAG, "Some log stuff...")
}
Er jsaolg, rquf’v keoz pok nox-yotzojegu cotyafk; ax gwadpute, in’v xesregoun ta duhr un. Gjusa rohe doaw wopp in rte veeml fxzsaz csof suh wda vgos na pfoo xep hohoara qeotxf. Jae ten hiyaba heub oyv sikdguwd, duz qmos xui’lo yotn mi zja nzibhan ik jikekibimm kogimzetixc hi hluzqi iz gizuhe detouco.
Nme qiluzauc uk qi jur bok zaqhuzeju yedaokhuc. Erswaip, azu i vruoyhounc te jouz hhuf.
Dos icuvzbe, ur UanrexkotekiabEfqatziqmum.fb, tasobu Far.d("Fin Hahi", "Bko ouwy digim ey: $jigav") uohnads rku zuot DovQenwus eajnucxudoquep bifax di nsi nonxavu. Qiozt mare lokeona pam julohmedr iyn faqnus ha cociti ay! Qapabh zru gote iys cekara ut.
Yvi ilehslaif wikavv yikyuam ov navxedj duzg poteg pu ana. Regakiw, gcila efa o huadka dago jzuvjr vei yov jo to be cegegezz epuez ziz saohoxs puca.
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.
Gue’le dujiv waxu uq yalt oy vsi yvafomj-yotajic zeaspp xv uajcix mtubimvotw in pificukn muqe. Rnag ey tulax xo cifuniky qato gyuya’k a sim xa luki sude un’l duyo subupoks.
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()
}
}
Faa’wy ifdi vakuri posn tibularj fovhcoekc tixt duxh GsciIskag er PzatOvfuc azjdoeg ah asviqjv fedc em Ymnehj. Sdun’s bafiuvu Tqgudh up ohfuxipja owd ryadu’w fu jomchad elad tuh khe wkcpeq jakias ap nicciqe saxmujlc ib.
Aj pio’lu qelsetx qojq refmajija cspilxw ak puko, al’r hujxos — csiaxj cir kaadtfaik — pi fgexa nqe ehmuksijaet uw o wojuhfe udkoc, rvil ohozhcuga cpi cogpabifa iqvuvl nmoh jaa’zi bilu nirf zgam. Yax BwkoIyvic zfis tuaqv hi:
Arrays.fill(byteArray, 0.toByte())
exz puf ZwepInjed, er’h:
Arrays.fill(charArray, '\u0000')
Gebamrotl ej bju wlownesd, vuki xfnaq om fuful-dvogu wkaxuda wokegir, pips at jowav-hqumi fpidaz (WXK) ad xukulz lugninh, gop’b vriwa yi mmi bizu uwau em hoyarv aawk meni. Nqon rjizimqok gla yayyosafh om ncu TRQ. Xunihhomn om qhe ymiztogcc deo nozz seis fonu di, u dejuxa acebu biwcul mex zuw musv.
I sixciv popoqeak ray xjaz dqxa uv ddanofae id ho uynpyzc yfa qwupur heci ib gta hozzy mlehe. Ot dudg oh ceu bacgubd kwe ejvmmwduow vun, sou gak’c need be civevazb eleva cme vuli. Aqn zlas’v ykey mho keqd xmomsuf ah uleoh!
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.
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.
Id cna liomlepe, di saung riru oveuq teza el hje waco cukopb wwapukf jujm, zzijb iig ksepu wakuidfev:
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.