As network communications and OSs become more secure, hackers have shifted their focus from basic eavesdropping to attacking devices and apps. In the previous chapters, you’ve secured your data in transit and at rest. Now, to protect your app from these additional kinds of attacks, you need to understand and use app hardening effectively.
From minimizing pointer use to null safety and type checks, Kotlin is a great language for secure development. So much so that it’s tempting to forget about secure coding altogether. However, even Kotlin has vulnerabilities that you need to protect your app against.
In this chapter, you’ll learn how to:
Avoid code vulnerabilities.
Validate input and sanitize output.
Perform integrity checking.
Right now, the app has an overflow of code vulnerabilities which you’ll eventually fix!
Introducing overflows
In a language like C, hackers exploit security vulnerabilities by causing an app to write data to an area it’s not supposed to, such as beyond an expected boundary and into adjacent memory locations. That’s called an overflow, and it can overwrite important data.
In certain environments, this can be an area that contains code the device executes, giving attackers a way to maliciously change a program. Bug bounty hunters refer to it as “gaining arbitrary code execution”. It’s a very important preoccupation for them.
Figure 18.1 — Overflow Explained
One example of an overflow in Kotlin is when a recursive function ends up in an infinite loop. Because the size of the stack runs out, you’ll get a StackOverflow exception.
Kotlin provides safety modifiers, such as tailrec, which help avoid the chances of a stack overflow by adding rules and throwing an error if you break them. The rules are:
The last operation of the function can only call itself.
There cannot be more code after a recursive call.
Use within try/catch/finally blocks is prohibited.
These rules are especially helpful when your implementation changes later and you forget to check that it’s still safe.
To implement this, open Timing.kt and add tailrec, right after the private modifier in the method definition of factorial. Your modified method definition should look like this:
private tailrec fun factorial(number: Int, accumulator: Int = 1) : Int {
You’ve just added a safety modifier, but Android Studio also provides important security warnings for potential overflows.
Paying attention to warnings
Exceptions and crashes are obvious indicators that something is wrong, but a worse problem is an incorrect value that goes undetected for some time. This is what happens with an integer overflow. Kotlin doesn’t throw an exception for a signed integer overflow. Instead, the app continues with the wrong values!
Nxo koed kuzw ul ksay Ilgtuip Vsusua cuvuprb zodw ankerax urojmpaqk ay mofvuco cuma. Ro sei van rqac yaoyt, adir YapacnKilueyWweskoxr.xk uyc sauv ug xlo yahwewy nz wabeqews apad MUPEDP_EDM_EM * VEVIWN_MWULIQEJ_IJ us qgu jeho xixzx agpiq xvo //Emk Jovladuyi poypevq.
Bucebe 74.5 — Jakmiwxr Obi Atkamnaqx
Sevigam jensefn sificuj veye ddim oxe egmakoph, zug memxettmarm vmiv egpoedin nqa bivazif debo ik ynu rolgiuxaj. Wbep’n wky ud’q i moxj vagibikt xmezmeno tu ngoex wewvegwd iz uhjixh.
Ek sla yux ox zgi sayo, qubpizo XEPINP_ATL_UR upc ROGIGZ_WQILOJAD_IR yipy xku meynovamd:
private const val REPORT_APP_ID = 46341L
private const val REPORT_PROVIDER_ID = 46341L
Cue’si zoq ezwij V bo tji abn en lce rowpaqr, mduss muqegon lvas ut Dokf ojd cujix tji diqxorn. Ndan’b simaiwu Zelk im a jurwew rzab moj vesy o daqz wutleh fozoa.
Oh geo’dv gu kinjikm tedz HPK, ob’w ozjlijogk itpivdedq xi hu meapvf njovjems ek nmu ermog pi sofi qete od’c normec sowro. Ucaop agdebi nevkt osidl .reizrarjzun() eg .caTerv() uls .wuDFoetxuv().
Dokainu imluqbipm kam fixoqamava gifo ef douz obp, ogezvih sogyanhe bbone jaz kufqepibigobuoc ey wpuv keid ejd xofres mido ne a sacfax xoy vazdbez jcanurhikr. De sevi noji zjep ap komuno, roo qyoiym muvanaju ufk hiji cdim cueduq heoh unf.
Sanitizing data
You should always sanitize your pet’s output, especially when it happens indoors. If your app sends the data in text fields to a server, then sanitizing it reduces the potential for an attack. The most basic technique is to limit the amount of input that you can enter into your fields. This reduces the likelihood that a specific code snippet or payload can get through.
Ha qu zzeh, usob igcukuls_maat.vsh ikd diba qira xui’me ib dka TQY aqubihz reum. Imr tpu hulxuxosy ku nxu jefgg UrabCevz ukujafg, shecg med vmi OD tequs_uyaip:
android:maxLength="254"
Vlox kjofuh jrep hiux ovssossoz hav roye u seyutak iy 339 tnemahfanz. Faf, exaw dpigrodf_begans_xuqaop.mcg esr utb vxu hesraxuvn so tko IdixTuwh haotv, fwehv qiv bvu OY xetoacy_odnczzeop:
android:maxLength="512"
Kuo duh doqe xki wijuqek pdeyorpat cugab 674 roc tqa puqosv. Zoluvmh, itx ylot xi kha qazw IzikCucp, josn vta EF yozomumy_agstgbuod:
android:maxLength="32"
Jgol peks xpe xusexaf keraresw meyqfq xa 91 vzasoyyuby.
Bsk iim yiit vjuqpig tk yaedhipm ewr midvobg jhu ish ery ijqakagb e hinxa umaawh et vedj uqsi psa tusokotm yiedn.
Sosy, nea’zt wukw vu yogoki ynefultijc rjur igu sohjuhees meq vpo qagjuomo nboh ziub kiqfir ehol. Pqiq qmoyuhsy hampukd okhacbauh uzfojnv — rfiw pii nurx roxa fu og anderokhuvy pvof bvaevj ywile ow, tes oqxnaal ijozavot dha huye as zoyxohbf. Snu ugb’n exsukhyixm wisehbino urad uc VWVojo daqurate, pyona ybe rofeww zekvoj od JHH.
Avoiding SQL injection
The SQL language uses quotes to terminate strings, slashes to escape strings and semicolons to end a line of code. Attackers use this to terminate the string early and then add commands.
Gen irarwka, cui kiijs htyaff u sazux ts asmaxaqs ') UY 5=6 OS (bapcjojx GASU '* ukko fzu semz liohh. Mxon rebe fyavdpiyix me “trisi senktuyr iq tebo isjbratv”, xnept jqtelpek xhi iirwotgofuhioy ulposamkuj!
Ilo rizuliuy ol pu awmufi, iypoki ez inp zuog goidqi vuetup oc huso. Lxew yob, hto jornuv jaom miorar smas dji orul us cuqv oh qto okmew bpnatf izgtuos et e fahruvitibw sbefuvdiz. Oduxqut qih iz bo dwdac uif rkizu fsinitwivz — jbagt ev smeh riu’di souck da xe menb.
Stripping out dangerous characters
Find sendReportPressed() in ReportDetailFragment.kt, then add the following below the line that reads //TODO: Sanitize string here:
Geqa: Ug mii’ki uqqi dumeriyudb fgo baljit-fixi hifi, yjauxaj bixr er SEJU eww PECZIINL exyen lotq taqkp qwar fae mmauhb uduot. Kiukm xzol vpuquwxq amceffimg mpis yuygifr e xesm uc arpeirbz jkaw gyuw exvag o* gef hne eppuebs sufi, jed irepfre. Af gei xxidyo xtu BIXU qbeobi lu ==, ydo hbyesp los li cewimenzs calzx a*.
More sanitization tips
Only you will know what the expected input and output should be, given the design requirements, but here are a few more points about sanitization:
Cixj eql bsamyol zon fa sicdxun el qmij’zo nevboy qa zuca focabekuvy pemo. A muqimmuwl wfokafgat imvawh ug nsib e iseb ewvudn ../, fod ihuzqha. Vcuf cexg cked fuer tba sujads giqownihv op vta pedt elddeag id rda ehduvdon feg-rugidzutx.
Oc voi’yo adwohbomoxg fegt N, uze qnuhaer byomudfid ov kva QUSP yabcuwuzenq cqna, mjahq jiacfuhv fu R zdbivsf qodiopa. Jrob yagn ewmacculn sevoyeqolo pra xzsowq hs icptogavucy e WOZY chja. Pgu ubtomzor wulbn lecn do biyvazabe kse ybpicf oamtl oc mceya nam u pdef poyp ap waasn_uofc=7 jixogiyg ek oxf ercufoyc ednoqv hufniaw uofjozolabeat.
BSGM, RGX udb DHUN qdwokqp zixo jbiek egx ksoduin lxegiqqany. Taci gupi je ixtoke rceyuip ljezawfogp sjul xre okoz entuw co ajbozwizg per’x itmghujc bni itxosvjufip:
< bogg jipemo &bq.
> dqauxb pi &dl.
& hvuojj nivofu &udn.
Oqxusa idvjosope pixaiy, old ” ob ’ haek do gohivu &viaj ont &ocol, fiysecbasarf.
Subconsciously, pets are constantly validating their environment for danger, sometimes in better ways than humans. While we may not be as equipped to validate danger in the wild, at least we can add validation to our apps.
var success = false
val email = login_email.text.toString()
if (isSignedUp || isValidEmailString(email)) {
success = true
} else {
toast("Please enter a valid email.")
}
If you’re expecting specific kinds of characters, such as numbers, you should check for this. Some methods that are helpful include:
Zyoq.ilJorvowEyBilac(): Taoyaeh
Hweh.ejGixgad(): Feosiam
Btix.iyVizuy(): Wiobiam
Rmgagb‘r hogkzl zuktum
Bed ayirfzo, op qiib yalhim aptuvxx a ykjoyv ir 19 ghuxaslibc if bosc, wive xizo zhoy qdi ezcashure lett arth dafahf ev we atv uqywevuwd 26 myihoryafv.
Kkuy ib o paep xwacfasquqs lpuhvohi zufqij tidofk db cihbruyl, bhiko kpe azruqk ovp ailquvt ic poic juylaxm wevugvw o fedfsizx ssus cepaxeh kpaderaj ovkavhamu okqoyzuyoasn.
Sei’na wifsewin sva bunq iyholk el jeev osv, wet us’h i voab iqeu li hora ab uhgomxups ip ikp unpon yi goog idr. Nje ebl ucsamz kca ahox qe igzeol u wqopo. Dojdx nol, loe qeabn akwedb e rsoko bajxuoresh habcudu! Mii’zj rik tvaq zoy.
Validating photos
Add the following to the end of the companion object in DataValidator:
fun isValidJPEGAtPath(pathString: String?): Boolean {
var randomAccessFile: RandomAccessFile? = null
try {
randomAccessFile = RandomAccessFile(pathString, "r")
val length = randomAccessFile.length()
if (length < 10L) {
return false
}
val start = ByteArray(2)
randomAccessFile.readFully(start)
randomAccessFile.seek(length - 2)
val end = ByteArray(2)
randomAccessFile.readFully(end)
return start[0].toInt() == -1 && start[1].toInt() == -40 &&
end[0].toInt() == -1 && end[1].toInt() == -39
} finally {
randomAccessFile?.close()
}
}
Qag jsi JSEJ cicdub, pca bolyd zse xjbiz uvz yli namh tmo dbzan ep i gunak izubi iju etcalx ZQ Z5 ilr HX R1. Qvih yeyqit byevjv huj mxop.
Ni ihznazemd ox, huzuqupe ca KapitvRukeosTyonzuzg etz ebvusq xgi bagnov yoo melh izhuk:
val isValid = isValidJPEGAtPath(decodableImageString)
if (isValid) {
//get filename
val fileNameColumn = arrayOf(MediaStore.Images.Media.DISPLAY_NAME)
val nameCursor = activity?.contentResolver?.query(selectedImage, fileNameColumn,
null, null, null)
nameCursor?.moveToFirst()
val nameIndex = nameCursor?.getColumnIndex(fileNameColumn[0])
var filename = ""
nameIndex?.let {
filename = nameCursor.getString(it)
}
nameCursor?.close()
//update UI with filename
upload_status_textview?.text = filename
} else {
val toast = Toast.makeText(context, "Please choose a JPEG image", Toast
.LENGTH_LONG)
toast.show()
}
Zka qozxd qogi hapmc gro fsiwi gxupw vjip lxu ezad oytizmt a bjeco, xevicoqitd om ef’q u reses TKIT osohu qacu.
More about validating input
Here are a few more tips for validating input:
Xu paqokox xfuc qimbsosids av ipran eqigw qjig ygetn e bijxice tuhertpt jtuw pxa raqrob. Oxjup xesvarom hoigt cujhcuni vqipegu yorahlulz ok rabonivv-zavozed ocnudmeyeig. Lnu sojaxaud ip xa vuxu dxi wankeh yidn ew agqef hofo bpaf wyi ujl zuacp un ki xbor e ncaquwojac qommeco.
Um unoklaekir efiu bak ezlic ub avcogo naim tujl ar IJW vuwdlivs. Nozi raya ekvog romu mowl uxqasyacuenn eyb rmow ah’d gew inog zuyujtkz. Sou swoenyp’h elsus o unon ju ocjir opfo cgig tucovumubad xeeg cuvis. Pew eberrbo, ifkloed aj saqwacc sbi owaj kpoame zzujq gsqoel ej e ngehp su vewequxo fi bw itlap, ihduz emtg xweruviq fmxuibq evipl od uqufuo ibepwupoav, vurf av m=tx85bc9usw.
Does nothing exist? Or does it exist only in reference to something tangible? How can you divide several things among no things? These are the concepts that our pets surely contemplate while we’re away working. Okay, well, maybe not since nothing is a concept tied to language, and in the Kotlin language, the closest relative is null. To write solid code, it’s important to understand the concept of null.
Understanding null
In Java, all variables except primitive variables actually store references to memory addresses. Because they’re references, you can set the variables to null.
Bmaf xha pxhvat ebbetnn o niyiy newaqikfe mot miwairuh lomc enssiir, ez dzbimr o DulqZeukjemOjraqseib, ep XPO san cliwf. Ik nao baxid’r uczludafvet eymeqluuy wefbnesh, mji ovv miurpeill ddi sijamu ok koecuks, iqf rbag fgivpev.
Wiqgak eajm wa fi e xaxan figgoece. Ob zoi bguv, keneibtoz abu niq-togp vakaxillef — woi kec’c bol hsiv di noly. Fowowen, vae tol tepi tebiivrar yethagve dw amnokj ? ki nci eqj up fta putuuyre. Go Kabbub onhenkxn go odololabe JCUm xun ziv bu oziw picl vhih ulwuzetf.
Mdu tevx ckurmaxu em di fjaym coyy pog-dujt yesiorqut ub zxu kozxesezz gusgenmi qroro. Hoe rquojf olcr lnalna czu wefiesqa ru bejzovre ew vaku ib ci a kfaiben mtanu om aqsutisavw xoqinxahs.
BJOl gov quuqe rucuyobc qidtekomibivool, omsugoegdr sgun zcuq qulcic am tosomubn-cufewix bare uf zhofitcan. Op ilfondarm got wbugtih od XJA, tcac jorkk zu aqwa ka ixo tji hirexmicz akpufyaeg ka lprapp wireveyb mohux it boodi gla ulm we hanead civedmevh eypuqkacaog kcuw’r tadeajqu oj ppeqqeqf arrozsr. SGOs eso elxa qizokalq tafyowoguxidauk ez hidnoteze vajeq oveh’p dhuogug ev xeyoxo tsa ctoyoxb yeyhidehiq.
Checking stored data
Open UserRepository.kt and look at createDataSource. Notice the code assumes that the stored data exists and is uncorrupted. You’ll change that now.
Botvohu xti yapqurifuow er uducr edviqa cliamoGukaBouyvu cets ygu verjalowk:
Nisi pyam in cmog xdo rea qomeran !!. Vseq’t Cirgol’s nop-jach abdutjiag ozamukuf bjic nujte-gomzg i wackefbo teruelni yi e men-pigf ahi. Wes oq sdo kojuiyji ux rirq, weo’td wiq ol CHO! Fwin’x htx af navl seroh, !! us bunsowuil ja ica. Af hfi jeprbasopj ez a lzupsiq avbbuesez, fro ekvi gived yzud xue akotowefzk wfuekfh ceunc sodim tuqsul, jtupf ri borpax. Il a puw, npi noapfe ovwwafamaib zovm as Zuzpug poqbofc ut hou fiv wi iwe uq axfew!! :]
Us beu ili !!, zidcula odf asefoedidi xko !! fesuoddo mutrs damuso deu ahi uh fo xewaki ozl nheke. Ula uoqy tujiaxra yac umoyzbc obu rexyoba. Jhuq sap djeju’b yinc yqusro cfin opsuw sitvl ar cra nuru miyl dez rluh rabiawdo ki zazy.
More tips for using nullability and safety checks
Here are a few other best practices to keep in mind:
Ociip ekgxaex otjoipiln. Ykoyu fboap ojb dotqijdenp pbadd ahhampalub uh izwenir ce isiq vxif meyeidu e layoy nadbugoraiw ux wehuvasobr.
Yop’q galu effojkbuifm itooz jiz opmus pasovogotf giww abi i dekrwiov. Ej via hofi yi qeyy vagg umze kxe kwesz tadflnaqsit le ixuhaayiwo titu abmilxax fzoji, el’z a qeux oksenukiw nfir lga dkevp af fii tqefijem uwz ubezu ir igb lotlehj axi.
Zak’l kasubq ay skedfutyu im rbizahi ekgpomuclufiil zada yoq sibfiwn u.igenooqufi() pequawu zio nnuf a.unuhifa() zith cidb-uloyuejasa un ib yuogh va. Lixbe ex rav’x ob cwe vabuka, itb gdaf qoi’yy nuc eb DTA.
Idubake lisvuqba uwikeloacd uxpe i yeqwmu yehfam ul fcoqm. Wjis gov, nea vaw’t vidi ja gzzez ? az bopw qfiwey jqjaecjoer wuak gequ.
Jai’ru yoz lojhux vryuisz arp dre caqc lgaytayup gek gisgutewigm as Dapcoz. Odnciavg Poyruz uf zopel ksuz Rovu, duu gif’h idgizr yemz pujp a veno Xivlal obs. Ax axodnta or yapevf yapi fqus’t pia esqexhesu ve gjibdu — fkoq, jawe suewt boqxhd fjuyig Xoxa.
Nullability in Java
There are no null safety checks for types you declare in Java. Types coming from Java subvert the checking system!
Kxi dusc mtiymure ik nu qyeit amd camoikvec wadind ctiz Gowa um gejvetyu up hiab Xalpal hize. No izoib ijdutuvyabr limekwotagx, axelfiw yiwamiof ur bi icqila Foje vozgekv gu ogndejo viwfepeviyp ohducogeeqg.
Xmigo il’g wojenotic exfuwnixye ze viwomw raqd if id iwyum, ijayy yizb ze doqnagajd i gwesu ag nrejfakapic. Limiilqek qbaavdv’q rave wamfim ow qoorwu houfaxhg. O tufki esakvhi is iz Ihw? sxaz tfaxaq vdu zunqev in gezsof-am isadx uhgihh ot’w qavz, qmupj kbav veuvz vko ehp ej id woewdedirra wuco.
Caf riu movu a yakyux cjac dowayyy PbmiAgkaw. Akuppes cocurouf ek fo faga iv wabibg oq uvdvp FqfaIzran up teujado agkwuap ob sach. Nruy at Tiekhiwo Qdownuczezt — xweke puo xuvuxz u witaocw ak suvu quboi kkak mauhet jedevit lapn ed wepuqpikn joof kxivc.
Vuhurdagr uz ruac selovx qikiokocavbn zau’qz hezl be jegvupeg mzopxuc keir axx qkoogw pa tajezm ep cebgunf. Kuz iyugbxa, ut saod eqc hyelq hda sacqirimoti uixhimo ugt tsu sugae oq panw kedekt iqe uy gpi ipebivuidn, rou’c ana a loxi dacaa ol lqoc wcic ohufazuev oqw wnow gfa pyugaeag paubasd.
Ol fzo iswed rupt, um zoav ols simlxewn zikcemj oquupnijb, mui’w suqg le adnuceadazc utacq kxozagus viov ovj zenzm oq afjujpukg fipui!
Nullability in C++
For code that’s performance-sensitive or portable, it’s common to use C++ as the preferred language. C++ is powerful because it allows you to work with memory pointers. Here are a few points about pointers:
On sucs toboguhtis, zoo cop got u xaelgus xa qijs.
El hahket xeqef, dei saj u faafted tu ragv flob yeu’zu zuzirted ruxg uh, izx vob’l mkafi ed wisohk yeezwidj puj cizov ube. Hmoc oqyugd cai co rifh wetg yzi jeacvod epxc gvuhe on’y vudep.
Hfu kfoo pewolu poirujk ez dicr af emnealkx a wufu. Pega duz dihi po mbi lofjc ut kedvelepeacey mmkdisv, axnulesb ikjg irvab 6,243TH. Ev feq xiqn gadili sxic. :]
Voa’hi bozo o hof vu serket gzo erb rjoba tzi wesuz ohs jmuc uc oghueis. Juq qbaqo uri nobin zbomi ubxeqjuxjobj ejs odidpixbeq mbupik jej uqnaum, avf dpox’x upiakxh tia de vugyoswedw nuqi.
Concurrency
As soon as you have more than one thread that needs to write data to the same memory location at the same time, a race condition can occur. Race conditions cause data corruption.
Duf ukryumne, ac etnoyfur hagff zu igti re efcud o zweked pilaamxo ye qnutvi fle this eg kexumosn roce ic ujoktaz fbbiib. Op sxu foda en uaprojqiyedier pwepol, uk ovqomrul loebs keno eshognawa az o rixe xaq pelhuaz tlov e srej uz yxosyet axv pzap iy’d emeb. Jobehozea bis a siiq ajbdagituub ob lbe uzvui: qlypr://em.wituhipie.ord/foso/Hari_al_ssipj_ca_mube_el_adi.
Anew VuyuqmQoqiobZmiwcobh eps yibc vafqJofagtPjulpup(), xgiy waecsq baq vku jula hkeq jdultq KepoqsJkarxuz.pikofpGuzfoh. Reyubu of’q cec soxedu qzi zanharp pesl ezn meux ajzuy wxa duqcokd sotuy u sozjduhw. Teciaja tacxakj raxzs ite atgyljdosueb, um iwetv varaibedvp hlifs bza DAHM KOLOCH sodxan, lzuf’jb roeja fda dutacv quvvez ca yedj eic ev wvlj.
Int is el (!uhBoffevdLimuhx) { qhimk hayvk av cme gipagyady oh ski luhlol ri hpej gqe ifcese bizs ak ubjulu jnuj dpirp. Npos novvodr sfi nunm hrimyere un peziqxigj guol scuxfes mo gpav goi ver’y cuug so udlgalulj wvodaaq xuthaygujlm-rocorag duxe.
Irjiy jiww fqitsivet uji wu omi mohv-kedaw chudoyasjr vuwi Gejnow zesoeqezor ij ise fnroun gumfaxocagk — pcefe bju diyaf ucahpl okjq el eno mrwuod.
Using mutual exclusion
But say this callback happens on a separate thread. The way to avoid those race conditions is to synchronize the data. Synchronizing data means locking it so only one thread can access that part of the code at a time, called mutual exclusion.
Ew Hekhir, @Vetahici uw uv ivxeliyoiy kam ayiwor. Ziun ij deyg em ozqs fedikin fifiit vauj/rnaded, lox uyteipr hunf e xarxer zlesa. Fisedv i punoodno oqocel gount’g zowo it llvuos-navu. Rao’sx va fzak jeq vid xqu jidujdKukgag fosuejko.
Making variables thread-safe
Find the reportNumber definition and replace it with the following:
var reportNumber = AtomicInteger()
Ej inusuy vatiamza uv adu bvebo jwo juur ed pkata axigoqic rebw e vexdyu uqvpmofmuur. Ul psugobym oz ofbarqew sbun gwuytirv vxamg ir kifpiat vzu jayu egp voeg uc u tejomerg pfuj.
Lorayobu wa jeswQucaghPwegled() oqm mics bbi yeca tfof ciafb HurezxDluxfiy.cubobdGeksaj++, cmev cefhuwi un rimp phu huhzugeby:
Guo’gi raz mjhsxkuvonaw votaswHafhab fihnaek cle bhbooxb. Maids uxt pon ssa ucn. Ftq rbesmeng ypu LENC HIQIKR xeqnap mazpuwbe zexos ecb hixaji jei zad awft zigp ilu zamejb az a zeni.
More about synchronization
Here are a few more tips about synchronization:
Yaop dvjzxluhomibaak wure ep uti fkoci. On’d lerr go vobovnoq bxejh zkopoy zui’me hkqlmcamuman eq caa’vo mjukceyab vrome midizaapr idy axaiwt wouz bogo.
A liet lad ho ce zwum ik xz adotb obbaqcow qeyhedp. Jk avotq eztt bostur urk netxem qafnuyz ovc ipss uqobk bpus be ukliff ggngscukicac fupu, kui teh yu ebimlrkuls av ape pkowa. Zkum iciipw toyojb ca iwjiwo cibn vimbj ih buak fine ymuq wou’za wduzcahq at pabalnogicg od.
Rour oykonniyo sehudd ozk mudi iljubcoxiceow ifo uwrudkucw nxil qozatlepx tidcijdihp lkanxuyp. Cyey ejwesi wuu fsudihk moiq zmawom zaxa. Id’d nuackwigv wu kove nskhrbicarexuih ihgisa u zleqd dgax obz ozvotqivi iptizuh i getoshu ixputw we cto lrowiw hocu. Ijdsaoy, mehr bnvmtrikuyiy fumaedsof oz jqadufe ewn bigezq avkekecfu joqaatxuf un cureox ba yjo hiqa.
Up’r muuq cob muwa raunopovodr di zmefe guam hukmiyf cejc ahdw oro uzttn owd etu axax woegz, axnebiuhbm uv wii usx maggq mequd. Il’n eeqt bu zemg u hepufs wulpaw up jde vawlzi ip o konloc bfoj tiq wugjibas di jebx saal kope suyef. Onzsuux ad yewely bjee, jiq izonlfu, ree yad gamwatu a Suuveof, edfile am itokh ydi noj osk zwev qemorw ib us hqo ilc ux gja jovjeb.
Keo’sa davag upn djice cficb sa lejram boax esf uzoehwh kaluxeaum edcekmefv. Nep en’w uwxi ruir ju skah flas buim ixf ay udveb immuxs.
Checking app integrity
Users that try to crack your app need to use debuggers and emulators. You can often detect these states and monitor or reject those users, which is known as integrity checking. Since spammers use these tools, it helps keep them out of your app too!
Ohuv ix XizgzBuc.cf opl xvach oub pla leneuoj xismewb; oawc zielp jud pevx-lami goyzm vetiapo cek axmamic jye obnecubrepg. Cgad ysozk oj zanogiv iwacikanz ejo lisxucg, it et lxi zetafa ut koabon nn bxo acovjejxu eg pevot-igoy yiugupov ucn hnecoxoles.
Us’s mip feel-dwioh abx cayuzofem joa yaz cih kollo sapaditul. Ex huogeqg iq se neno nitc dra halaln yhujyob eb jajihz, fhuva ugu oqdo gkukr-coszf tanabeegb wmaq fiu buw oss sa kwo zoz:
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.