Programovanie

Zabezpečenie a overovateľ triedy

Tento mesiac článok pokračuje v diskusii o bezpečnostnom modeli Javy, ktorá sa začala v auguste filmu „Pod kapotou“. V tomto článku som poskytol všeobecný prehľad bezpečnostných mechanizmov zabudovaných do virtuálneho stroja Java (JVM). Pozorne som sa pozrel aj na jeden aspekt týchto bezpečnostných mechanizmov: zabudované bezpečnostné prvky JVM. V septembrovom filme „Pod kapotou“ som preskúmal architektúru nakladača tried, čo je ďalší aspekt vstavaných bezpečnostných mechanizmov JVM. Tento mesiac sa zameriam na tretí výbežok bezpečnostnej stratégie JVM: overovateľ triedy.

Verifikátor súboru triedy

Každý virtuálny stroj Java má overovač súborov triedy, ktorý zaručuje, že načítané súbory triedy majú správnu vnútornú štruktúru. Ak overovateľ súboru triedy zistí problém so súborom triedy, vyvolá výnimku. Pretože súbor triedy je iba sekvenciou binárnych údajov, nemôže virtuálny stroj vedieť, či bol súbor konkrétnej triedy vygenerovaný dobre mieneným kompilátorom Java alebo tienistými crackermi zameranými na narušenie integrity virtuálneho stroja. V dôsledku toho majú všetky implementácie JVM overovač súborov triedy, ktorý je možné vyvolať na nedôveryhodných triedach, aby sa zaistilo bezpečné použitie tried.

Jedným z bezpečnostných cieľov, ktoré pomáha overovač súborov triedy dosiahnuť, je robustnosť programu. Ak kompilátor buginy alebo dôvtipný cracker vygeneroval súbor triedy obsahujúci metódu, ktorej bajtkódy obsahovali inštrukciu na preskočenie konca metódy, mohla by táto metóda, ak by bola vyvolaná, spôsobiť zlyhanie virtuálneho stroja. Z dôvodu robustnosti je preto dôležité, aby virtuálny stroj overil integritu importovaných bajtových kódov.

Aj keď môžu návrhári virtuálnych strojov Java rozhodnúť, kedy ich virtuálne stroje vykonajú tieto kontroly, mnoho implementácií vykoná väčšinu kontrol hneď po načítaní triedy. Takýto virtuálny stroj analyzuje bytecodes (a overuje ich integritu) raz, predtým, ako sa vôbec vykonajú. V rámci overovania bytových kódov zabezpečuje virtuálny stroj Java všetky pokyny na skok - napríklad ísť do (skok vždy), ifeq (skok, ak je vrchol zásobníka nula) atď. - spôsobí skok na inú platnú inštrukciu v prúde bytecode metódy. V dôsledku toho nemusí virtuálny stroj kontrolovať platný cieľ zakaždým, keď sa stretne s inštrukciou skoku pri vykonávaní bajtových kódov. Vo väčšine prípadov je kontrola všetkých bytových kódov raz pred ich vykonaním efektívnejším spôsobom na zabezpečenie robustnosti ako kontrola každej inštrukcie bytecode pri každom vykonaní.

Verifikátor súboru triedy, ktorý vykonáva kontrolu čo najskôr, s najväčšou pravdepodobnosťou pracuje v dvoch odlišných fázach. Počas fázy jedna, ktorá sa uskutoční hneď po načítaní triedy, overovateľ súboru triedy skontroluje vnútornú štruktúru súboru triedy vrátane kontroly integrity bajtových kódov, ktoré obsahuje. Počas fázy dva, ktorá prebieha pri vykonávaní bajtových kódov, overovač súboru triedy potvrdzuje existenciu symbolicky odkazovaných tried, polí a metód.

Fáza jedna: Interné kontroly

Počas prvej fázy overovateľ súboru triedy skontroluje všetko, čo je možné skontrolovať v súbore triedy, a to tak, že sa pozrie iba na samotný súbor triedy (bez toho, aby skúmal akékoľvek iné triedy alebo rozhrania). Prvá fáza overovača súborov triedy zaisťuje, že importovaný súbor triedy je správne sformovaný, vnútorne konzistentný, dodržiava obmedzenia programovacieho jazyka Java a obsahuje bajtové kódy, ktoré bude pre spustenie virtuálneho stroja Java bezpečné. Ak overovateľ súboru triedy zistí, že nič z toho nie je pravda, spôsobí chybu a program triedy nikdy nepoužije súbor triedy.

Kontrola formátu a vnútornej konzistencie

Okrem overenia integrity bytových kódov overovateľ počas prvej fázy vykonáva veľa kontrol správneho formátu súborov triedy a vnútornej konzistencie. Napríklad každý súbor triedy musí začínať rovnakými štyrmi bajtmi, magické číslo: 0xCAFEBABE. Účelom magických čísel je uľahčiť analyzátorom súborov rozpoznávanie určitého typu súborov. Prvá vec, ktorú verifikátor súborov triedy pravdepodobne skontroluje, je teda to, že importovaný súbor skutočne začína 0xCAFEBABE.

Verifikátor súboru triedy tiež skontroluje, či súbor triedy nie je skrátený ani vylepšený o ďalšie koncové bajty. Aj keď rôzne súbory triedy môžu mať rôznu dĺžku, každá jednotlivá súčasť obsiahnutá v súbore triedy označuje jej dĺžku a typ. Overovateľ môže pomocou typov a dĺžok komponentov určiť správnu celkovú dĺžku pre každý súbor triedy jednotlivcov. Týmto spôsobom môže overiť, či má importovaný súbor dĺžku zodpovedajúcu jeho vnútornému obsahu.

Overovateľ tiež sleduje jednotlivé komponenty, aby sa ubezpečil, že sú dobre tvarovanými inštanciami svojho typu komponentu. Napríklad deskriptor metódy (návratový typ metódy a počet a typy jej parametrov) je uložený v súbore triedy ako reťazec, ktorý musí dodržiavať určitú bezkontextovú gramatiku. Jednou z kontrol, ktoré overovateľ vykonáva na jednotlivých komponentoch, je skontrolovať, či je každý deskriptor metódy dobre tvarovaný reťazec príslušnej gramatiky.

Okrem toho overovateľ súboru triedy kontroluje, či trieda sama dodržiava určité obmedzenia, ktoré na ňu kladie špecifikácia programovacieho jazyka Java. Napríklad overovateľ presadzuje pravidlo, že všetky triedy okrem triedy Objekt, musí mať nadtriedu. Overovač súborov triedy teda za behu kontroluje niektoré z pravidiel jazyka Java, ktoré sa mali vynútiť v čase kompilácie. Pretože overovateľ nemá žiadny spôsob, ako zistiť, či bol súbor triedy vygenerovaný benevolentným kompilátorom bez chýb, kontroluje každý súbor triedy, aby sa ubezpečil, že sa pravidlá dodržiavajú.

$config[zx-auto] not found$config[zx-overlay] not found