Programmering

Sikkerhet og klasselasterarkitekturen

Forrige 1 2 Side 2 Side 2 av 2

Klasselastere og navneplasser

For hver klasse den lastes, holder JVM oversikt over hvilken klasselaster - enten det er primordialt eller objekt - lastet klassen. Når en lastet klasse først refererer til en annen klasse, ber den virtuelle maskinen om referanseklassen fra samme klasselaster som opprinnelig lastet referanseklassen. For eksempel hvis den virtuelle maskinen laster inn klassen Vulkan gjennom en bestemt klasselaster, vil den prøve å laste inn noen klasser Vulkan refererer til gjennom samme klasselaster. Hvis Vulkan refererer til en klasse som heter Lava, kanskje ved å påkalle en metode i klassen Lava, vil den virtuelle maskinen be om Lava fra klasselaster som lastet Vulkan. De Lava klasse returnert av klasselaster er dynamisk knyttet til klasse Vulkan.

Fordi JVM tar denne tilnærmingen til lasting av klasser, kan klasser som standard bare se andre klasser som ble lastet av samme klasselaster. På denne måten lar Java-arkitekturen deg lage flere navn-mellomrom inne i et enkelt Java-program. Et navneområde er et sett med unike navn på klassene som er lastet av en bestemt klasselaster. For hver klasselaster opprettholder JVM et navneplass som er fylt med navnene på alle klassene som er lastet gjennom den klasselasteren.

Når en JVM har lastet inn en klasse som heter Vulkan inn i et bestemt navneplass, for eksempel er det umulig å laste inn en annen klasse som heter Vulkan inn i det samme navneplassen. Du kan laste inn flere Vulkan klasser inn i en JVM, men fordi du kan opprette flere navneområder i et Java-program. Du kan gjøre det ganske enkelt ved å opprette flere klasselastere. Hvis du oppretter tre separate navneplasser (ett for hver av de tre klasselasterne) i et Java-program som kjører, ved å laste inn et Vulkan klasse i hvert navneplass, kan programmet lastes inn tre forskjellige Vulkan klasser i søknaden din.

En Java-applikasjon kan instantiere flere klasse lasterobjekter enten fra samme klasse eller fra flere klasser. Det kan derfor skape så mange (og så mange forskjellige typer) klasse lasterobjekter som det trenger. Klasser lastet av forskjellige klasselaster er i forskjellige navneområder og kan ikke få tilgang til hverandre med mindre applikasjonen eksplisitt tillater det. Når du skriver et Java-program, kan du adskille klasser lastet fra forskjellige kilder i forskjellige navneområder. På denne måten kan du bruke Java sin klasselasterarkitektur til å kontrollere enhver interaksjon mellom kode lastet fra forskjellige kilder. Du kan forhindre at fiendtlig kode får tilgang til og undergraver vennlig kode.

Klasselastere for appletter

Et eksempel på dynamisk utvidelse med klasselastere er nettleseren, som bruker klasselasterobjekter for å laste ned klassefilene for en applet over et nettverk. En nettleser avfyrer et Java-program som installerer et klasselasterobjekt - vanligvis kalt en applet class loader - som vet hvordan man kan be om klassefiler fra en HTTP-server. Applets er et eksempel på dynamisk utvidelse, fordi når Java-applikasjonen starter, vet den ikke hvilke klassefiler nettleseren vil be den laste ned over hele nettverket. Klassefilene som skal lastes ned bestemmes på kjøretid, ettersom nettleseren møter sider som inneholder Java-appletter.

Java-applikasjonen startet av nettleseren oppretter vanligvis et annet appletklasselasterobjekt for hvert sted i nettverket det henter klassefiler fra. Som et resultat lastes klassefiler fra forskjellige kilder av forskjellige klasselasterobjekter. Dette plasserer dem i forskjellige navneplasser i Java-applikasjonen. Fordi klassefilene for appleter fra forskjellige kilder er plassert i separate navneområder, er koden til en ondsinnet applet begrenset fra å forstyrre direkte klassefiler som er lastet ned fra andre kilder.

Samarbeid mellom klasselastere

Ofte er et klasselasterobjekt avhengig av andre klasselastere - i det minste på den opprinnelige klasselasteren - for å hjelpe det med å oppfylle noen av klasselastforespørslene som kommer. Tenk deg for eksempel at du skriver et Java-program som installerer en klasselaster hvis spesielle måte å laste klassefiler på oppnås ved å laste dem ned over et nettverk. Anta at det i løpet av kjøringen av Java-applikasjonen blir bedt om klasselaster for å laste en klasse som heter Vulkan.

En måte du kan skrive klasselaster er å få den til å be den første klasselasteren om å finne og laste klassen fra det pålitelige depotet. I dette tilfellet, siden Vulkan ikke er en del av Java API, anta at den primordial class loader ikke finner en klasse som heter Vulkan. Når den opprinnelige klasselasteren reagerer på at den ikke kan laste klassen, kan klasselasteren din prøve å laste den Vulkan klasse på sin egendefinerte måte, ved å laste den ned over nettverket. Forutsatt at klasselaster var i stand til å laste ned klasse Vulkan, det Vulkan klassen kan da spille en rolle i applikasjonens fremtidige løpetid.

For å fortsette med det samme eksemplet, anta at det en tid senere er en metode for klassingen Vulkan blir påkalt for første gang, og at metoden refererer til klasse String fra Java API. Fordi det er første gang referansen brukes av det kjørende programmet, spør den virtuelle maskinen klasselaster (den som lastet Vulkan) å laste String. Som før overfører klasselaster først forespørselen til primordial class loader, men i dette tilfellet er primordial class loader i stand til å returnere en String klasse tilbake til klasselaster.

Urklasselasteren trengte sannsynligvis ikke å laste String på dette punktet fordi, gitt det String er en så grunnleggende klasse i Java-programmer, den ble nesten helt sikkert brukt før og derfor allerede lastet. Mest sannsynlig returnerte urklasselasteren nettopp String klasse som den tidligere hadde lastet fra det pålitelige depotet.

Siden primordial class loader kunne finne klassen, prøver ikke class loader å laste den ned over nettverket. den overgår bare til den virtuelle maskinen String klasse returnert av primordial class loader. Fra det tidspunktet bruker den virtuelle maskinen det String klasse når som helst klasse Vulkan refererer til en klasse som heter String.

Klasselastere i sandkassen

I Javas sandkasse er klasselasterarkitekturen den første forsvarslinjen mot ondsinnet kode. Det er tross alt klasselasteren som bringer kode inn i JVM - koden som kan være fiendtlig.

Klasselasterarkitekturen bidrar til Java's sandkasse på to måter:

  1. Det forhindrer skadelig kode i å forstyrre velvillig kode.
  2. Det beskytter grensene til de pålitelige klassebibliotekene.

Klasselasterarkitekturen beskytter grensene til de pålitelige klassebibliotekene ved å sørge for at ikke-klarerte klasser ikke kan late som de er pålitelige. Hvis en ondsinnet klasse med hell kunne lure JVM til å tro at det var en klarert klasse fra Java API, kunne den ondsinnede klassen potensielt bryte gjennom sandkassebarrieren. Ved å forhindre at ikke-klarerte klasser etterligner pålitelige klasser, blokkerer klasselasterarkitekturen en potensiell tilnærming til å kompromittere sikkerheten til Java-kjøretiden.

Navneplasser og skjold

Klasselasterarkitekturen forhindrer at ondsinnet kode forstyrrer velvillig kode ved å tilby beskyttede navneplasser for klasser lastet av forskjellige klasselaster. Som nevnt ovenfor, navneplass er et sett med unike navn for lastede klasser som vedlikeholdes av JVM.

Navneplasser bidrar til sikkerhet fordi du faktisk kan plassere et skjold mellom klassene lastet inn i forskjellige navneplasser. Inne i JVM kan klasser i samme navn-rom samhandle med hverandre direkte. Klasser i forskjellige navnerom kan imidlertid ikke engang oppdage hverandres tilstedeværelse med mindre du eksplisitt gir en mekanisme som gjør at klassene kan samhandle. Hvis en ondsinnet klasse, en gang lastet, hadde garantert tilgang til alle andre klasser som for øyeblikket er lastet av den virtuelle maskinen, kan den klassen potensielt lære ting den ikke burde vite, eller den kan forstyrre riktig utførelse av programmet ditt.

Å skape et sikkert miljø

Når du skriver et program som bruker klasselaster, oppretter du et miljø der den dynamisk lastede koden kjører. Hvis du vil at miljøet skal være fritt for sikkerhetshull, må du følge visse regler når du skriver applikasjonen og klasselasterne. Generelt sett vil du skrive søknaden din slik at ondsinnet kode blir beskyttet mot velvillig kode. Du vil også ønske å skrive klasselastere slik at de beskytter grensene til pålitelige klassebiblioteker, som for eksempel Java API.

Navneplasser og kodekilder

For å få sikkerhetsfordelene som tilbys ved navn-mellomrom, må du sørge for at du laster klasser fra forskjellige kilder gjennom forskjellige klasselaster. Dette er ordningen, beskrevet ovenfor, brukt av Java-aktiverte nettlesere. Java-applikasjonen avfyrt av en nettleser oppretter vanligvis et annet applet-klasselasterobjekt for hver kilde av klasser det lastes ned over nettverket. For eksempel vil en nettleser bruke ett klasselasterobjekt til å laste ned klasser fra //www.niceapplets.com, og et annet klasselasterobjekt for å laste ned klasser fra //www.meanapplets.com.

Vokter begrensede pakker

Java lar klasser i samme pakke gi hverandre spesielle tilgangsrettigheter som ikke blir gitt til klasser utenfor pakken. Så hvis klasselasteren din mottar en forespørsel om å laste inn en klasse som med navnet frimodig erklærer seg som en del av Java API (for eksempel en klasse som heter java.lang.Virus), skal klasselasteren din gå forsiktig frem. Hvis lastet, kan en slik klasse få spesiell tilgang til de pålitelige klassene i java.lang og kan muligens bruke den spesielle tilgangen til lure formål.

Derfor vil du normalt skrive en klasselaster slik at den ganske enkelt nekter å laste inn en klasse som hevder å være en del av Java API (eller et annet pålitelig kjøretidsbibliotek), men som ikke finnes i det lokale klarerte depotet. Med andre ord, etter at klasselaster har sendt en forespørsel til primordial class loader, og primordial class loader indikerer at den ikke kan laste klassen, bør class loader sjekke for å sikre at klassen ikke erklærer seg selv som medlem av en pålitelig pakke. Hvis den gjør det, bør klasselaster din, i stedet for å prøve å laste ned klassen over nettverket, kaste et sikkerhets unntak.

Å beskytte forbudte pakker

I tillegg kan det hende du har installert noen pakker i det klarerte depotet som inneholder klasser du vil at applikasjonen din skal kunne lastes gjennom primordial class loader, men som du ikke vil være tilgjengelig for klasser lastet gjennom class loader. Anta for eksempel at du har opprettet en pakke med navnet absolutt kraft og installerte den på det lokale depotet som er tilgjengelig for den primordial class loader. Anta også at du ikke vil at klasser lastet av klasselaster skal kunne laste noen klasse fra absolutt kraft pakke. I dette tilfellet vil du skrive klasselaster slik at det aller første det gjør er å sørge for at den valgte klassen ikke erklærer seg selv som medlem av absolutt kraft pakke. Hvis en slik klasse blir bedt om, bør klasselasteren din, i stedet for å overføre klassenavnet til den primordiale klasselasteren, kaste et sikkerhets unntak.

Den eneste måten en klasselaster kan vite om en klasse er fra en begrenset pakke, for eksempel java.lang, eller en forbudt pakke, for eksempel absolutt kraft, er med navnet på klassen. Dermed må en klasselaster få en liste over navnene på begrensede og forbudte pakker. Fordi navnet på klassen java.lang.Virus indikerer at det er fra java.lang pakke, og java.lang er på listen over begrensede pakker, bør klasselasteren kaste et sikkerhets unntak hvis primordial class loader ikke kan laste den. Likeledes fordi navnet på klassen absolutepower.FancyClassLoader indikerer at den er en del av absolutt kraft pakken, og absolutt kraft pakken er på listen over forbudte pakker, bør klasselaster din kaste et sikkerhets unntak.

En sikkerhetsinnstilt klasselaster

En vanlig måte å skrive en sikkerhetsinnstilt klasselaster er å bruke følgende fire trinn:

  1. Hvis det finnes pakker som denne klasselasteren ikke har lov til å laste fra, sjekker klasselasteren om den forespurte klassen er i en av de forbudte pakkene nevnt ovenfor. I så fall kaster det et sikkerhets unntak. Hvis ikke fortsetter den til trinn to.

  2. Klasselasteren overfører forespørselen til den første klasselaster. Hvis den opprinnelige klasselasteren returnerer klassen, returnerer klasselasteren den samme klassen. Ellers fortsetter den til trinn tre.

  3. Hvis det finnes pålitelige pakker som denne klasselasteren ikke har lov til å legge til klasser i, sjekker klasselasteren om den forespurte klassen er i en av disse begrensede pakkene. I så fall kaster det et sikkerhets unntak. Hvis ikke fortsetter den til trinn fire.

  4. Til slutt prøver klasselaster å laste klassen på den tilpassede måten, for eksempel ved å laste den ned over et nettverk. Hvis det lykkes, returnerer det klassen. Hvis det ikke lykkes, kaster det feilen "ingen klassedefinisjon funnet".

Ved å utføre trinn ett og tre som beskrevet ovenfor, beskytter klasselaster grensen til de pålitelige pakkene. Med trinn ett forhindrer det at en klasse fra en forbudt pakke blir lastet i det hele tatt. Med trinn tre tillater det ikke en ikke-klarert klasse å sette seg inn i en pålitelig pakke.

Konklusjon

Klasselasterarkitekturen bidrar til JVMs sikkerhetsmodell på to måter:

  1. ved å skille koden i flere navneplasser og plassere et "skjold" mellom koden i forskjellige navneplasser
  2. ved å beskytte grensene til pålitelige klassebiblioteker, for eksempel Java API

Begge disse funksjonene i Java's class loader-arkitektur må brukes riktig av programmerere for å høste sikkerhetsfordelen de tilbyr. For å dra nytte av navneplassskjoldet, bør kode fra forskjellige kilder lastes gjennom forskjellige klasse lasterobjekter. For å dra nytte av pålitelig grensevern for pakker, må klasselastere skrives slik at de sjekker navnene på etterspurte klasser mot en liste over begrensede og forbudte pakker.

For en gjennomgang av prosessen med å skrive en klasselaster, inkludert eksempelkode, se Chuck McManis's JavaWorld artikkel, "Grunnleggende om Java-klasselastere."

Neste måned

I neste måneds artikkel fortsetter jeg diskusjonen om JVMs sikkerhetsmodell ved å beskrive klasseverifisereren.

Bill Venners har skrevet programvare profesjonelt i 12 år. Basert i Silicon Valley, tilbyr han programvarekonsulent- og opplæringstjenester under navnet Artima Software Company. Gjennom årene har han utviklet programvare for forbrukerelektronikk, utdanning, halvleder og livsforsikringsindustri. Han har programmert på mange språk på mange plattformer: monteringsspråk på forskjellige mikroprosessorer, C på Unix, C ++ på Windows, Java på nettet. Han er forfatter av boka: Inside the Java Virtual Machine, utgitt av McGraw-Hill.

Lær mer om dette emnet

  • Boken Spesifikasjonen for den virtuelle Java-maskinen (//www.aw.com/cp/lindholm-yellin.html), av Tim Lindholm og Frank Yellin (ISBN 0-201-63452-X), en del av Java-serien (//www.aw.com/cp /javaseries.html), fra Addison-Wesley, er den definitive referansen til Java-virtuell maskin.
  • Sikker databehandling med JavaNow og fremtiden (en whitepaper) // www.javasoft.com/marketing/collateral/security.html
  • Vanlige spørsmål om applets sikkerhet

    //www.javasoft.com/sfaq/

  • Lav nivå sikkerhet i Java, av Frank Yellin //www.javasoft.com/sfaq/verifier.html
  • Hjemmesiden til Java Security

    //www.javasoft.com/security/

  • Se den fiendtlige applets hjemmesiden

    //www.math.gatech.edu/~mladue/HostileApplets.html

  • Boken Java SecurityHostile-appletter, hull og motgift, av Dr. Gary McGraw og Ed Felton, gir en grundig analyse av sikkerhetsspørsmål rundt Java. //www.rstcorp.com/java-security.html
  • Tidligere "Under The Hood" -artikler:
  • The Lean, Mean Virtual Machine - Gir en introduksjon til Java virtuelle maskin.
  • Java Class File Lifestyle - Gir en oversikt over Java-klassefilen, filformatet som alle Java-programmer er samlet inn i.
  • Java's Garbage- Collected Heap - Gir en oversikt over søppelinnsamling generelt og søppelinnsamlet dyngen til den virtuelle Java-maskinen spesielt.
  • Grunnleggende om Bytecode - Introduserer bykodene til den virtuelle Java-maskinen, og diskuterer primitive typer, konverteringsoperasjoner og stackoperasjoner spesielt.
  • Floating Point Arithmetic - Beskriver den virtuelle Java-maskinens flytpunktstøtte og bytekodene som utfører flytende punktoperasjoner.
  • Logikk og aritmetikk - Beskriver den virtuelle Java-maskinens støtte for logisk og heltallsregning, og relaterte bytekoder.
  • Objekter og matriser - Beskriver hvordan den virtuelle Java-maskinen håndterer objekter og matriser, og diskuterer relevante bytekoder.
  • Unntak - Beskriver hvordan den virtuelle Java-maskinen håndterer unntak, og diskuterer relevante bytekoder.
  • Prøv-til slutt - Beskriver hvordan den virtuelle Java-maskinen implementerer prøve-endelige klausuler, og diskuterer relevante bytekoder.
  • Control Flow - Beskriver hvordan den virtuelle Java-maskinen implementerer kontrollflyt og diskuterer relevante bytekoder.
  • The Architecture of Aglets - Beskriver det indre arbeidet til aglets, IBMs autonome Java-baserte agent for teknologi.
  • The Point of Aglets - Analyserer virkeligheten av mobile agenter som aglets, IBMs autonome Java-baserte programvareagenteknologi.
  • Method Invocation and Return - Beskriver de fire måtene den virtuelle Java-maskinen påkaller metoder, inkludert relevante bytekoder.
  • Trådsynkronisering - Viser hvordan trådsynkronisering fungerer i Java virtuelle maskin. Diskuterer bytekodene for å gå inn og ut av skjermer.
  • Java's Security Architecture - Gir en oversikt over sikkerhetsmodellen innebygd i JVM og ser på JVMs innebygde sikkerhetsfunksjoner.

Denne historien, "Security and the class loader architecture" ble opprinnelig utgitt av JavaWorld.

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