Даведайцеся больш пра бяспечнае захаванне жэтонаў у Android

У якасці пралога да гэтага артыкула я хацеў бы працытаваць кароткі сказ для выдуманага чытача. Гэтая цытата будзе важнай, калі мы рухаемся наперад.

Не існуе такога паняцця, як абсалютная бяспека. Бяспека - гэта комплекс мер, якія абапіраюцца адзін на аднаго і спалучаюцца, каб запаволіць непазбежнае.

Амаль тры гады таму я напісаў запіс з ідэямі пра тое, як абараніць радкі-токены ад гіпатэтычнага зламысніка, які разбівае наша прыкладанне для Android. Дзеля памяці і каб пазбегнуць непазбежнай смерці Інтэрнэту, я ўзнаўляю тут некалькі раздзелаў.

Адзін з найбольш распаўсюджаных выпадкаў выкарыстання адбываецца ў тым выпадку, калі нашаму дадатку неабходна мець зносіны з вэб-сэрвісам для абмену дадзенымі. Гэты абмен дадзенымі можа змяняцца ад менш канфідэнцыяльнага да больш адчувальнага тыпу і можа мяняцца ў залежнасці ад запыту на рэгістрацыю, запыту на змяненне дадзеных карыстальніка і г.д.

Абсалютная першая мера, якая прымяняецца, - гэта выкарыстанне злучэння SSL (Secure Sockets Layer) паміж кліентам і серверам. Вярніцеся да арыгінальнай прапановы. Гэта не гарантуе абсалютнай прыватнасці і бяспекі, хаця гэта добрая першая праца.

Калі вы выкарыстоўваеце злучэнне SSL (напрыклад, калі вы бачыце шафку ў сваім браўзэры), гэта азначае, што сувязь паміж вамі і серверам зашыфравана. Тэарэтычна нішто не можа атрымаць доступ да інфармацыі, якая змяшчаецца ў гэтых запытах (*)

(*) Ці казаў я, што абсалютнай бяспекі не існуе? Падключэнні SSL па-ранейшаму могуць быць парушаны. Гэты артыкул не дае вычарпальнага спісу ўсіх магчымых нападаў, але хачу расказаць пра некалькі спосабаў. Падробленыя сертыфікаты SSL і атакі "ў цэнтры".

Пойдзем далей. Мы мяркуем, што наш кліент падтрымлівае сувязь з нашым сэрвісам праз зашыфраваны канал SSL. Яны абменьваюцца карыснымі дадзенымі, вядуць бізнес і радуюцца. Аднак мы хацелі б забяспечыць дадатковы ўзровень бяспекі.

Наступным лагічным крокам, які выкарыстоўваецца сёння, з'яўляецца прадастаўленне маркера аўтэнтыфікацыі альбо ключа API для выкарыстання ў зносінах. Вось як гэта працуе. Наш бэкенд атрымлівае петыцыю. Як даведацца, што хадайніцтва паходзіць ад аднаго з нашых правераных кліентаў, а не ад выпадковых хлопцаў, якія спрабуюць атрымаць доступ да нашага API? Дадатак правярае, ці прадастаўляе кліент сапраўдны ключ API. Калі папярэдняя заява дакладная, мы працягваем запыт. У адваротным выпадку мы адхіляем гэта і прымаем некаторыя карэкціруючыя меры ў залежнасці ад характару нашай дзейнасці (у гэтым выпадку я хацеў бы захаваць IP-адрас і ідэнтыфікатар кліента, каб даведацца, як часта гэта адбываецца. Калі частата перавышае гэтую, пажадана мая добры густ, я думаю пра забарону альбо гляджу менавіта тое, чаго спрабуе дамагчыся грубы хлопец у Інтэрнэце).

Давайце пабудуем наш замак з-пад зямлі. У нашым дадатку мы, верагодна, дадамо зменную назву API_KEY, якая будзе аўтаматычна ўстаўлена ў кожны запыт (калі вы карыстаецеся Android, верагодна, у вашым кліенце для пераабсталявання).

прыватная канчатковая статычная радок API_KEY = "67a5af7f89ah3katf7m20fdj202"

Гэта выдатна і працуе, калі мы хочам прайсці аўтэнтыфікацыю нашых кліентаў. Праблема ў тым, што няма самога эфектыўнага пласта.

Калі вы будзеце дэкампіляваць прыкладанне з apktool і шукаць радкі, вы знойдзеце наступнае ў адным з атрыманых .smali файлаў:

const-string v1, "67a5af7f89ah3katf7m20fdj202"

Так, упэўнены. Гэта не прынята лічыць маркерам праверкі, таму нам усё роўна трэба зрабіць уважлівы агляд, каб вырашыць, як дасягнуць гэтай радкі і ці можна яе выкарыстоўваць для мэт праверкі сапраўднасці. Але вы ведаеце, куды я іду: гэта ў асноўным пытанне часу і рэсурсаў.

Ці можа Proguard дапамагчы нам замацаваць гэты радок, каб нам не трэба хвалявацца? Не зусім. Proguard у сваім FAQ задаецца тым, што шыфраванне радкоў не цалкам магчыма.

Наконт захавання гэтай радкі ў адным з іншых механізмаў, прадугледжаных Android, напрыклад Б. агульныя перавагі? Наўрад ці гэта добрая ідэя. Да SharedPreferences можна лёгка атрымаць доступ праз эмулятар або ўкараненне прылад. Некалькі гадоў таму хлопец па імі Шрынівас прадэманстраваў, як можна змяніць вынік у відэагульні. Тут нам не хапае варыянтаў!

Кітайскі камплект для развіцця (NDK)

Я збіраюся разабрацца з арыгінальнай мадэллю, якую я прапанаваў тут, і пра тое, як мы можам прайсці гэта, каб забяспечыць больш бяспечную альтэрнатыву. Давайце ўявім дзве функцыі, якія могуць быць выкарыстаны для шыфравання і дэшыфравання нашых дадзеных:

Тут няма нічога асаблівага. Абедзве гэтыя функцыі патрабуюць ключавога значэння і радка для кадавання або дэкадавання. Вы вяртаеце зашыфраваны або расшыфраваны маркер. Мы назвалі наступную функцыю:

Вы адгадваеце кірунак? Гэта правільна. Пры неабходнасці мы маглі б шыфраваць і дэшыфраваць маркер. Гэта забяспечвае дадатковы ўзровень бяспекі: калі код заблытаны, гэта ўжо не так проста, як выкананне пошуку радкоў і праверка асяроддзя, у якім знаходзіцца радок. Але вы ўсё яшчэ можаце высветліць праблему, якую трэба вырашыць?

Вы можаце?

Дайце яму яшчэ некалькі секунд, калі вы яшчэ гэтага не зразумелі.

Так, вы маеце рацыю. У нас ёсць ключ шыфравання, які таксама захоўваецца ў выглядзе радка. Гэта павышае бяспеку праз абфуксацыю, але мы ўсё яшчэ маем маркер для простага тэксту, незалежна ад таго, выкарыстоўваецца гэты маркер для шыфравання ці сам маркер.

Зараз давайце скарыстаемся NDK і паўторым наш механізм бяспекі.

З дапамогай NDK мы можам атрымаць доступ да кода C ++ з дапамогай нашага кода Android. Давайце хвіліну, каб падумаць, што рабіць. У нас можа быць родная функцыя C ++, якая захоўвае ключ API або іншыя важныя дадзеныя, якія мы спрабуем захаваць. Гэтая функцыя можа быць выклікана пазней з кода, і радок не захоўваецца ні ў адным файле Java. Гэта забяспечыла б аўтаматычную абарону ад метадаў дэкампіляцыі.

Наша функцыя C ++ будзе выглядаць так:

Яго проста называюць у кодзе Java:

І функцыя шыфравання / дэшыфравання называецца як у наступным фрагменце:

Калі мы ведаем, што мы ствараем APK, засланяючы яго, раскладаючы і спрабуючы атрымаць доступ да радка, якая змяшчаецца ў роднай функцыі getSecretKey (), мы не можам знайсці яе! Перамога?

Не зусім. Код NDK можа быць разабраны і правераны. Гэта стане больш складаным, і вам спатрэбяцца ўсё больш сучасныя інструменты і метады. Вы выдалілі 95% дзяцей сцэнарыя, але каманда, якая валодае дастатковымі рэсурсамі і матывацыяй, усё яшчэ можа атрымаць доступ да маркера. Вы памятаеце гэты прысуд?

Не існуе такога паняцця, як абсалютная бяспека. Бяспека - гэта комплекс мер, якія абапіраюцца адзін на аднаго і спалучаюцца, каб запаволіць непазбежнае.
Вы ўсё яшчэ можаце атрымаць доступ да разабранага кода радка літаральна!

Напрыклад, Hex Rays можа вельмі добра дэкампіляваць родныя файлы. Я ўпэўнены, што існуе шэраг інструментаў, якія могуць дэканструяваць любы Android, які ствараецца роднай кодам (я не звязаны з Hex Rays, і не атрымліваю ад іх ніякай фінансавай кампенсацыі).

Такім чынам, якое рашэнне мы можам выкарыстоўваць для зносін паміж бэкэндам і кліентам без пазнакі?

Стварайце ключ у рэжыме рэальнага часу на прыладзе.

Ваша прылада не павінна захоўваць ніякія ключы і не павінна мець справу з раздражняльнай абаронай літаральнага радка! Гэта вельмі старая тэхніка, якая выкарыстоўваецца такімі службамі, як выдаленая праверка ключоў.

  1. Кліент ведае функцыю (), якая вяртае ключ.
  2. Зваротны шлях ведае функцыю, рэалізаваную ў кліенце ()
  3. Кліент выкарыстоўвае функцыю () для стварэння ключа, які перадаецца на сервер.
  4. Сервер правярае яго і працягвае запыт.

Ці злучаеш ты кропкі? Замест таго, каб мець родную функцыю, якая вяртае вам радок (лёгка вызначыць), чаму б не функцыю, якая вяртае вам суму трох выпадковых простых лікаў ад 1 да 100? Ці функцыя, якая паказвае бягучы дзень у час Unix і дадае 1 да кожнай лічбы? Як наконт атрымання кантэкстнай інфармацыі з прылады, напрыклад B. Аб'ём памяці, які выкарыстоўваецца для дасягнення больш высокага ўзроўню энтрапіі?

Апошні абзац утрымлівае шэраг ідэй, але, спадзяюся, наш гіпатэтычны чытач трапіў у адзнаку.

Рэзюмэ

  1. Не існуе такога паняцця, як абсалютная бяспека.
  2. Спалучэнне некалькіх ахоўных мер з'яўляецца закладам высокага ўзроўню бяспекі.
  3. Не захоўвайце строкавыя літаралы ў кодзе.
  4. Выкарыстоўвайце NDK для стварэння самастойна створанага ключа.

Вы памятаеце першае прапанову?

Не існуе такога паняцця, як абсалютная бяспека. Бяспека - гэта комплекс мер, якія абапіраюцца адзін на аднаго і спалучаюцца, каб запаволіць непазбежнае.

Я хацеў бы яшчэ раз падкрэсліць, што ваша мэта - як мага лепш абараніць ваш код, не губляючы пункту гледжання таго, што 100% бяспека недасягальная. Аднак, калі вы здольныя абараніць свой код, каб запатрабаваць мноства рэсурсаў, каб расшыфраваць усю важную інфармацыю, вы можаце спаць добра і спакойна.

Невялікая адмова ад адказнасці

Я ведаю. Вы зайшлі так далёка і разгледзелі ўвесь артыкул пра тое, як гэты хлопец не згадаў пра Dexguard і перажыў усе праблемы. Вы маеце рацыю Dexguard сапраўды можа замаскіраваць радкі, і яны робяць у іх вельмі добрую працу. Аднак цэны на Dexguard могуць быць празмернымі. Я выкарыстаў Dexguard у папярэдніх кампаніях з крытычнымі сістэмамі бяспекі, але гэта можа быць не для ўсіх. І чым больш магчымасцей у распрацоўцы праграмнага забеспячэння і жыцця, тым багацей і багацей становіцца свет.

Атрымлівайце задавальненне ад кадавання!

Я пішу свае думкі пра праграмнае забеспячэнне і жыццё ў цэлым у сваім акаўнце ў Twitter. Калі вам спадабаўся гэты артыкул альбо вам ён дапамог, не саромейцеся, падзяліцеся ім ♥ і / альбо пакіньце каментар. Гэта валюта, якую рухаюць аўтары самадзейнасці.