Mstari mmoja wa kodi unaweza kuharibu mfumo wako mzima wa udhibiti wa ufikiaji (access control model). Ukichanganya mwili wa ombi (request body) moja kwa moja kwenye mchakato wa kusasisha hifadhidata, unakuwa umempa mteja kalamu ya kuandika upya schema yako. Hiyo ndiyo Mass Assignment. Si hitilafu ya ajabu au tukio la nadra. Ni kushindwa kwa usanifu (design failure) kunakotokea kila wakati API inapochukua payload kama sera yake yenyewe ya kusasisha.
await db.users.update(req.params.id, { ...req.body });
Inaonekana safi. Inapunguza kazi ya kuandika. Lakini mteja ndiye anayechagua funguo (keys). Mshambuliaji anaweza kuongeza "role": "admin", "accountId": "someone_else", au "credit": 99999" kwenye mchakato wa kawaida wa kusasisha wasifu. Tabaka lako la uhakiki (validation layer) linaweza kukagua ikiwa thamani hizo ni maandishi (strings) au namba na kusema zinaonekana sawa. Hata hivyo, uhalali (validity) si ruhusa (authorization). Mtumiaji anaweza kuwa na umiliki halali wa rekodi husika. Hiyo haimaanishi kuwa anapaswa kuwa na haki ya kuhariri kila kipengele kilichomo ndani yake.
Jinsi Mass Assignment Inavyoonekana Hali Halisi
Hatari imejificha kwenye urahisi. Frameworks na ORMs hufanya iwe rahisi sana kuunganisha funguo za JSON moja kwa moja kwenye safu (columns) za hifadhidata. Unapofanya hivi, unaiambia hifadhidata kuamini mteja kuhusu nini kinapaswa kubadilika, na si tu jinsi kinavyopaswa kubadilika.
Mtumiaji anayesasisha wasifu wake anaweza kutuma data halali kwa displayName na bio, lakini akaingiza role au balance pamoja nazo. Ikiwa controller yako inapitisha tu kitu (object) hicho, hifadhidata itaandika vyote. Uhakiki (validation) hukamata thamani zisizo sahihi. Mara chache hukamata funguo zenye nia mbaya. Kanuni ya biashara inayosema "mtumiaji huyu anaruhusiwa kusasisha wasifu wake" inakuwa ruhusa ya jumla juu ya kila safu katika mstari huo.
Suluhisho si kuongeza uhakiki zaidi. Ni usanifu thabiti zaidi.
Milango Mitatu
Mabadiliko salama hupitia ukaguzi watatu tofauti kabla hayajagusa hifadhi.
Vipengele Vilivyokubaliwa (Allowlist)
Anza kwa kuamua ni funguo gani hasa utazitazama. Ikiwa kipengele hakipo kwenye orodha ya kuruhusiwa (allowlist), kataa ombi au ondolea funguo hiyo. Hii inabadilisha msimamo wa msingi: safu mpya za hifadhidata haziwezi kuandikwa mpaka mwanaloji (developer) azifungue waziwazi. Schema hukua kadiri muda unavyopita. Mwanachama wa timu anaweza kuongeza stripeCustomerId, departmentBudget, au alama ya isVerified. Kwa kutumia allowlist, safu hizo mpya zinalindwa kiotomatiki dhidi ya maandishi kutoka kwa mteja. Bila hiyo, kila safu mpya inakuwa sehemu ya API inayoweza kushambuliwa kwa bahati mbaya.
Thamani Halali
Mara tu unapojua ni vipengele gani vinaruhusiwa, kagua ikiwa thamani hizo zinaingia akilini. Je, mfululizo wa timezone ni timezone inayotambulika? Je, barua pepe imekaa kama barua pepe? Je, namba iko katika kiwango kinachokubalika? Hii ni usafi wa data (hygiene). Inazuia takataka kuingia kwenye mfumo wako, lakini haizuia matumizi mabaya. Mfululizo wa "admin" ambao ni halali kabisa bado ni hatari kwenye kipengele cha role ikiwa mtu asiyestahili ameituma.
Mabadiliko Yaliyoidhinishwa
Hii ndiyo mlango ambao timu nyingi hulipuuza, na ndipo ulinzi wa kweli ulipo. Uliza swali la kina: je, mhusika huyu mahususi ana ruhusa ya kubadilisha kipengele hiki mahususi kwenye rekodi hii mahususi? Si "je, mtumiaji ni admin?" Si "je, mtumiaji ana upeo wa write:users?" Badala yake, "je, mtumiaji huyu anaruhusiwa kubadilisha displayName yake mwenyewe, lakini kamwe asibadilishe accountId yake?" Idhinisho la kila kipengele (per-field authorization) huzuia ruhusa pana kama "Editor" au "User" isigeuke kuwa ufunguo mkuu wa kila sifa katika mstari huo.
Kujenga Kazi ya Patch (Patch Function)
Unganisha milango mitatu katika mchakato mmoja (pipeline). Ombi la patch linapofika, lipitishe katika hatua hizo kwa mpangilio.
Kwanza, chuja pembejeo (input) dhidi ya allowlist yako. Ikiwa role si kipengele kinachoruhusiwa kwa endpoint hii, acha hapo hapo. Hakuna sababu ya kuhakiki au kuidhinisha thamani ambayo hupaswi kuipokea kamwe.
Pili, hakiki thamani zilizoruhusiwa. Kagua aina (types), mifumo (formats), na kanuni za biashara. Kipengele cha eneo lazima kiwe maandishi yanayotambulika kama timezone halisi. URL ya avatar lazima iwe URI halali chini ya urefu fulani.
Tatu, idhinisha kitendo. Hakikisha kuwa mhusika anamiliki rekodi husika, au anamiliki ruhusa kamili inayohitajika kwa kipengele hiki. Umiliki ni chaguo bora la msingi kwa data binafsi, lakini baadhi ya vipengele bado vinahitaji milango ya ziada. Mtumiaji anaweza kumiliki wasifu wake, lakini ni admin wa malipo pekee anayepaswa kugusa taxRegion.
Nne, sawazisha data (normalize). Ondoa nafasi zisizohitajika (whitespace), rudisha nafasi zinazojirudia, badilisha barua pepe kuwa herufi ndogo, au ondoa herufi za udhibiti (control characters). Fanya hivi baada ya uhakiki lakini kabla ya kuhifadhi ili usilinganishe maandishi machafu wakati wa ukaguzi wa idhinisho.
Ikiwa ingizo litashindwa katika lango lolote, kataa mabadiliko (mutation) yote. Usitumie sehemu ya uga (fields) salama na kuacha zile mbaya kimyakimya. Jibu mchanganyiko huwafundisha wateja (clients) kurusha kila ufunguo (key) wanaoweza kufikiria na kuona lipi litakubalika. Shindwa kwa uwazi.
Hali za Kipekee (Edge Cases) Zinazojali Kweli
Ulinzi dhidi ya mass assignment unategemea maelezo madogo ambayo majaribio ya kitengo (unit tests) mara nyingi hupuuza.
Vifunguo vya JSON vinavyojirudia. Washambuliaji wanaweza kutuma data (payloads) kama {"role": "user", "role": "admin"}. Kulingana na mchanganuzi (parser) wako wa HTTP na mfumo (framework), thamani ya pili inaweza kufuta ya kwanza kabla ya kodi yako ya programu kuiona hiyo object. Jaribu tabia hii katika kiwango cha mchanganuzi. Ikiwa mfumo wako unakubali ufunguo wa mwisho kimyakimya, orodha yako ya kuruhusu (allowlist) inaweza kuwa inaangalia "user" wakati hifadhidata inapokea "admin".
Object zilizojificha (nested objects), null, na array. Usichukulie kuwa data (payload) ni bapa (flat). Mteja anaweza kufunika uga uliowekewa vizuizi ndani ya object iliyojificha kama { "profile": { "role": "admin" } }. Orodha yako ya kuruhusu lazima ifuate mfuatano huo (recurse) ikiwa schema yako inafanya hivyo. Vivyo hivyo, amua jinsi unavyoshughulikia null. Je, inamaanisha "potezea uga huu" au "futa uga huu"? Na ikiwa array inatarajiwa, je, mthibitishaji (validator) wako unakataa miundo isiyotarajiwa, au unageuza object moja kuwa array na kuiruhusu ipite?
Uwiano wa Unicode (Unicode normalization). Virai (strings) viwili vinaweza kuonekana sawa kwa binadamu huku vikiwa na mfuatano tofauti wa byte. Mtumiaji anaweza kutuma é iliyounganishwa au e iliyotenganishwa pamoja na alama ya msisitizo. Ikiwa ukaguzi wako wa idhini (authorization) unafanya uwiano mara moja lakini tabaka lako la hifadhi linafanya uwiano tofauti, unaweza kuishia na data isiyo na msimamo au, mbaya zaidi, njia ya kukwepa ulinzi ambapo mgongano wa majina ya watumiaji unapita kwenye mantiki yako. Fanya uwiano mapema na ufanye uwiano kwa msimamo.
Hali za mashindano (Race conditions). Maamuzi ya idhini si picha tuli. Hutokea katika wakati fulani. Maombi (requests) mawili yanaweza kusoma rekodi ile ile, yote yakiona kuwa mtendaji anaruhusiwa kuandika, na yote yakatoa mabadiliko. Katikati ya hapo, hali au ruhusa za mtendaji zinaweza kuwa zimebadilika. Kila wakati tumia mabadiliko ya hifadhidata kwa kutumia sharti la namba ya toleo (version number) au thamani ya mashine ya hali (state machine). Tumia kitu kama UPDATE users SET ... WHERE id = ? AND version = 5. Ikiwa mstari ulibadilika tangu ulipousoma, uandishi utashindwa. Shughulikia kushindwa huku kwa kujaribu tena au kukataa. Hii inazuia ukaguzi wa idhini wa zamani usiharibu data yako.
Fuatilia Kinachojali
Huwezi kulinda kile usichoweza kukiona. Jenga uandishi wako wa ukaguzi (audit logging) kuzunguka uamuzi, siyo tu tendo.
Rekodi (Log) ID ya mtendaji na ID ya lengo. Rekodi majina kamili ya uga yaliyokubaliwa na yale yaliyokataliwa. Rekodi toleo la sera (policy version) lililofanya uamuzi na matokeo ya mwisho. Ikiwa mtumiaji ghafla anaanza kukataliwa role katika sasisho la wasifu wake, unataka kujua mara moja.
Kamwe usirekodi bearer tokens. Kamwe usitupe miili yote ya maombi (request bodies) kwenye kumbukumbu zako. Ukaguzi (audit trail) unapaswa kukusaidia kuchunguza matumizi mabaya, si kuwa ghala la siri za ufikiaji (credentials) na data binafsi.
Kanuni Pekee Unayohitaji
Mwili wa ombi (request body) unapendekeza data. Haujulishi mamlaka yake yenyewe. Mteja anaweza kuomba chochote. Seva yako huamua, uga kwa uga na mstari kwa mstari, nini kinaruhusiwa kuingia kwenye hifadhi ya kudumu. Jenga marekebisho (patches) yako ukiwa na mgawanyo huo akilini, na mass assignment itakuwa tatizo ambalo ulilizuia muda mrefu kabla halijafika kwenye tabaka lako la idhini.
