Programmering

Sikkerhed og klasselæsserarkitektur

Forrige 1 2 Side 2 Side 2 af 2

Klasselæssere og navneområder

For hver klasse, den indlæses, holder JVM styr på, hvilken klasselæsser - uanset om det er primordialt eller objekt - indlæst klassen. Når en indlæst klasse først henviser til en anden klasse, anmoder den virtuelle maskine om den refererede klasse fra den samme klasselæsser, der oprindeligt indlæste referenceklassen. For eksempel hvis den virtuelle maskine indlæser klasse Vulkan gennem en bestemt klasselæsser vil den forsøge at indlæse alle klasser Vulkan henviser til gennem den samme klasselæsser. Hvis Vulkan henviser til en klasse med navnet Lavamåske ved at påberåbe sig en metode i klassen Lava, vil den virtuelle maskine anmode om Lava fra klasselæsseren, der blev indlæst Vulkan. Det Lava klasse, der returneres af klasselæsseren, er dynamisk forbundet med klassen Vulkan.

Da JVM tager denne tilgang til indlæsning af klasser, kan klasser som standard kun se andre klasser, der blev indlæst af den samme klasselæsser. På denne måde giver Java's arkitektur dig mulighed for at oprette flere navne-mellemrum inde i et enkelt Java-program. Et navneområde er et sæt unikke navne på de klasser, der er indlæst af en bestemt klasselæsser. For hver klasselæsser opretholder JVM et navneområde, der er befolket med navnene på alle de klasser, der er blevet indlæst gennem denne klasselæsser.

Når en JVM har indlæst en klasse med navnet Vulkan i et bestemt navneområde, er det for eksempel umuligt at indlæse en anden klasse, der hedder Vulkan ind i det samme navne-rum. Du kan indlæse flere Vulkan klasser i en JVM, fordi du kan oprette flere navne-mellemrum inde i en Java-applikation. Du kan gøre det ganske enkelt ved at oprette flere klasselæssere. Hvis du opretter tre separate navnepladser (et for hver af de tre klasselæssere) i et kørende Java-program, så ved at indlæse et Vulkan klasse i hvert navneområde, kan dit program indlæse tre forskellige Vulkan klasser i din ansøgning.

En Java-applikation kan instantiere flere klasselæsserobjekter enten fra samme klasse eller fra flere klasser. Det kan derfor oprette så mange (og så mange forskellige slags) klasseindlæsningsobjekter, som det har brug for. Klasser indlæst af forskellige klasselæssere er i forskellige navneområder og kan ikke få adgang til hinanden, medmindre applikationen udtrykkeligt tillader det. Når du skriver et Java-program, kan du adskille klasser indlæst fra forskellige kilder i forskellige navneområder. På denne måde kan du bruge Java's klasselæssearkitektur til at kontrollere enhver interaktion mellem kode indlæst fra forskellige kilder. Du kan forhindre fjendtlig kode i at få adgang til og undergrave venlig kode.

Klasselæssere til applets

Et eksempel på dynamisk udvidelse med klasselæssere er webbrowseren, der bruger klasselæsserobjekter til at downloade klassefilerne til en applet på tværs af et netværk. En webbrowser affyrer et Java-program, der installerer et klasselæsserobjekt - normalt kaldet en applet klasse loader - der ved, hvordan man anmoder om klassefiler fra en HTTP-server. Applets er et eksempel på dynamisk udvidelse, for når Java-applikationen starter, ved den ikke, hvilke klassefiler browseren beder den downloade over hele netværket. Klassefilerne, der skal downloades, bestemmes ved kørselstid, da browseren støder på sider, der indeholder Java-applets.

Java-applikationen, der startes af webbrowseren, opretter normalt et andet appletklasse-indlæserobjekt for hver placering på netværket, hvorfra det henter klassefiler. Som et resultat indlæses klassefiler fra forskellige kilder af forskellige klasseindlæserobjekter. Dette placerer dem i forskellige navneområder i Java-applikationen. Da klassefiler til applets fra forskellige kilder er placeret i separate navneområder, er koden for en ondsindet applet begrænset fra at interferere direkte med klassefiler, der downloades fra enhver anden kilde.

Samarbejde mellem klasselæssere

Ofte er et klasselæsserobjekt afhængigt af andre klasselæssere - i det mindste på den oprindelige klasselæsser - for at hjælpe det med at opfylde nogle af de klassebelastningsanmodninger, der kommer på sin vej. Forestil dig f.eks. At du skriver et Java-program, der installerer en klasselæsser, hvis særlige måde at indlæse klassefiler på opnås ved at downloade dem over et netværk. Antag, at i løbet af Java-applikationen køres der en anmodning fra din klasselæsser om at indlæse en klasse, der hedder Vulkan.

En måde, du kan skrive klasselæsseren på, er at lade den først bede den oprindelige klasselæsser om at finde og indlæse klassen fra sit betroede arkiv. I dette tilfælde siden Vulkan er ikke en del af Java API, antag at den oprindelige klasselæsser ikke kan finde en klasse med navnet Vulkan. Når den oprindelige klasselæsser reagerer på, at den ikke kan indlæse klassen, kan din klasselæsser derefter forsøge at indlæse Vulkan klasse på sin brugerdefinerede måde ved at downloade den over hele netværket. Forudsat at din klasselæsser var i stand til at downloade klasse Vulkan, at Vulkan klasse kunne derefter spille en rolle i applikationens fremtidige gennemførelsesforløb.

For at fortsætte med det samme eksempel antager du, at det en tid senere er en klassemetode Vulkan påberåbes for første gang, og at metoden henviser til klasse Snor fra Java API. Fordi det er første gang, at referencen bruges af det kørende program, spørger den virtuelle maskine din klasselæsser (den, der blev indlæst Vulkan) at indlæse Snor. Som før videregiver din klasselæsser først anmodningen til primordial class loader, men i dette tilfælde er primordial class loader i stand til at returnere en Snor klasse tilbage til din klasselæsser.

Den oprindelige klasselæsser behøvede sandsynligvis ikke faktisk at indlæse Snor på dette tidspunkt fordi, givet det Snor er sådan en grundlæggende klasse i Java-programmer, den blev næsten helt sikkert brugt før og derfor allerede indlæst. Mest sandsynligt returnerede den oprindelige klasselæsser netop Snor klasse, som det tidligere var indlæst fra det betroede lager.

Da den oprindelige klasselæsser kunne finde klassen, forsøger din klasselæsser ikke at downloade den over hele netværket. det overgår blot til den virtuelle maskine Snor klasse returneret af den oprindelige klasselæsser. Fra det tidspunkt bruger den virtuelle maskine det Snor klasse når klasse Vulkan henviser til en klasse, der hedder Snor.

Klasselæssere i sandkassen

I Java's sandkasse er klasselæsserarkitekturen den første forsvarslinje mod ondsindet kode. Det er klasselæsseren, der trods alt bringer kode ind i JVM - koden, der kan være fjendtlig.

Klasselæsserarkitekturen bidrager til Java's sandkasse på to måder:

  1. Det forhindrer ondsindet kode i at forstyrre den velvillige kode.
  2. Det beskytter grænserne for de betroede klassebiblioteker.

Klasselæsserarkitekturen beskytter grænserne for de betroede klassebiblioteker ved at sikre, at ikke-tillidte klasser ikke kan foregive at være tillid til. Hvis en ondsindet klasse med succes kunne narre JVM til at tro, at det var en betroet klasse fra Java API, kunne den ondsindede klasse potentielt bryde gennem sandkassebarrieren. Ved at forhindre, at ikke-betroede klasser efterligner pålidelige klasser, blokerer klasselæsserarkitekturen en potentiel tilgang til at kompromittere sikkerheden ved Java-runtime.

Navn-mellemrum og skjolde

Klasselæsserarkitekturen forhindrer ondsindet kode i at forstyrre velvillig kode ved at tilvejebringe beskyttede navneområder til klasser, der er indlæst af forskellige klasselæssere. Som nævnt ovenfor, navn-mellemrum er et sæt unikke navne til indlæste klasser, der vedligeholdes af JVM.

Navne-mellemrum bidrager til sikkerhed, fordi du faktisk kan placere et skjold mellem klasser indlæst i forskellige navn-rum. Inde i JVM kan klasser i samme navne-rum interagere direkte med hinanden. Klasser i forskellige navneområder kan dog ikke engang registrere hinandens tilstedeværelse, medmindre du eksplicit giver en mekanisme, der gør det muligt for klasserne at interagere. Hvis en ondsindet klasse, når den var indlæst, havde garanteret adgang til alle andre klasser, der i øjeblikket er indlæst af den virtuelle maskine, kunne den klasse potentielt lære ting, den ikke skulle kende, eller den kunne forstyrre den korrekte udførelse af dit program.

Oprettelse af et sikkert miljø

Når du skriver et program, der bruger klasselæssere, opretter du et miljø, hvor den dynamisk indlæste kode kører. Hvis du vil have miljøet fri for sikkerhedshuller, skal du følge visse regler, når du skriver din applikation og klasselæssere. Generelt vil du skrive din applikation, så ondsindet kode bliver beskyttet mod velvillig kode. Du vil også gerne skrive klasselæssere, så de beskytter grænserne for pålidelige klassebiblioteker, som f.eks. Java API.

Navn-mellemrum og kodekilder

For at få de sikkerhedsfordele, der tilbydes af navnepladser, skal du sørge for at indlæse klasser fra forskellige kilder gennem forskellige klasselæssere. Dette er den ordning, der er beskrevet ovenfor, brugt af Java-aktiverede webbrowsere. Java-applikationen, der er affyret af en webbrowser, opretter normalt et andet applet-klasselæsserobjekt for hver klasse af klasser, det downloades over hele netværket. For eksempel vil en browser bruge et klasselæsserobjekt til at downloade klasser fra //www.niceapplets.com, og et andet klasselasterobjekt til at downloade klasser fra //www.meanapplets.com.

Beskyttelse af begrænsede pakker

Java tillader klasser i samme pakke at give hinanden særlige adgangsrettigheder, der ikke tildeles klasser uden for pakken. Så hvis din klasselæsser modtager en anmodning om at indlæse en klasse, der ved sit navn frækt erklærer sig selv som en del af Java API (for eksempel en klasse med navnet java.lang.Virus), skal din klasselæsser gå forsigtigt frem. Hvis det er indlæst, kan en sådan klasse få særlig adgang til de betroede klasser af java.lang og muligvis kunne bruge den specielle adgang til løgnagtige formål.

Derfor vil du normalt skrive en klasselæsser, så den simpelthen nægter at indlæse en klasse, der hævder at være en del af Java API (eller ethvert andet pålideligt runtime-bibliotek), men som ikke findes i det lokale betroede lager. Med andre ord, når din klasselæsser har sendt en anmodning til den oprindelige klasselæsser, og den oprindelige klasselæsser angiver, at den ikke kan indlæse klassen, skal din klasselæsser kontrollere for at sikre, at klassen ikke erklærer sig medlem af en pålidelig pakke. Hvis det gør det, skal din klasselæsser i stedet for at prøve at downloade klassen over hele netværket kaste en sikkerhedsundtagelse.

Beskyttelse af forbudte pakker

Derudover har du muligvis installeret nogle pakker i det betroede lager, der indeholder klasser, du vil have din applikation til at kunne indlæse gennem den oprindelige klasselæsser, men som du ikke ønsker at være tilgængelig for klasser, der er indlæst gennem din klasselæsser. Antag for eksempel, at du har oprettet en pakke med navnet absolut magt og installerede det på det lokale lager, der er tilgængeligt af den oprindelige klasselæsser. Antag også, at du ikke vil have klasser, der er indlæst af din klasselæsser, for at kunne indlæse nogen klasse fra absolut magt pakke. I dette tilfælde ville du skrive din klasselæsser således, at det allerførste, det gør, er at sikre, at den anmodede klasse ikke erklærer sig selv som medlem af absolut magt pakke. Hvis der anmodes om en sådan klasse, skal din klasselæsser, i stedet for at overføre klassens navn til den primære klasselæsser, kaste en sikkerhedsundtagelse.

Den eneste måde en klasselæsser kan vide, om en klasse er fra en begrænset pakke, f.eks java.lang, eller en forbudt pakke, såsom absolut magt, hedder klassen. Således skal en klasselæsser have en liste over navnene på begrænsede og forbudte pakker. Fordi navnet på klassen java.lang.Virus angiver, at det er fra java.lang pakke og java.lang er på listen over begrænsede pakker, skal din klasselæsser kaste en sikkerhedsundtagelse, hvis den oprindelige klasselæsser ikke kan indlæse den. Ligeledes fordi navnet på klassen absolutepower.FancyClassLoader angiver, at det er en del af absolut magt pakke og absolut magt pakke er på listen over forbudte pakker, din klasselæsser skal kaste en sikkerhedsundtagelse.

En sikkerhedsindstillet klasselæsser

En almindelig måde at skrive en sikkerhedsindstillet klasselæsser på er at bruge følgende fire trin:

  1. Hvis der findes pakker, som denne klasselæsser ikke har tilladelse til at indlæse fra, kontrollerer klasselæsseren, om den ønskede klasse er i en af ​​de forbudte pakker, der er nævnt ovenfor. I så fald kaster det en sikkerhedsundtagelse. Hvis ikke, fortsætter det med trin to.

  2. Klasselæsseren videresender anmodningen til den oprindelige klasselæsser. Hvis den oprindelige klasselæsser med succes returnerer klassen, returnerer klasselæsseren den samme klasse. Ellers fortsætter det med trin tre.

  3. Hvis der findes pålidelige pakker, som denne klasselæsser ikke har tilladelse til at tilføje klasser til, kontrollerer klasselæsseren, om den anmodede klasse er i en af ​​disse begrænsede pakker. I så fald kaster det en sikkerhedsundtagelse. Hvis ikke, fortsætter det til trin fire.

  4. Endelig forsøger klasselæsseren at indlæse klassen på den tilpassede måde, f.eks. Ved at downloade den over et netværk. Hvis det lykkes, returnerer det klassen. Hvis det ikke lykkes, kaster det fejlen "ingen klassedefinition fundet".

Ved at udføre trin et og tre som beskrevet ovenfor beskytter klasselæsseren grænserne for de pålidelige pakker. Med trin et forhindrer det overhovedet, at en klasse fra en forbudt pakke kan indlæses. Med trin tre tillader det ikke, at en ikke-betroet klasse kan indsætte sig selv i en pålidelig pakke.

Konklusion

Klasselæsserarkitekturen bidrager til JVM's sikkerhedsmodel på to måder:

  1. ved at adskille kode i flere navne-mellemrum og placere et "skjold" mellem kode i forskellige navn-rum
  2. ved at beskytte grænserne for pålidelige klassebiblioteker, såsom Java API

Begge disse funktioner i Java's klasselæssearkitektur skal bruges korrekt af programmører for at høste den sikkerhedsfordel, de tilbyder. For at udnytte navnet-space-skjoldet, skal kode fra forskellige kilder indlæses gennem forskellige klasse-loader-objekter. For at drage fordel af pålidelig pakkegrænsebeskyttelse skal klasselastere skrives, så de kontrollerer navnene på de anmodede klasser mod en liste over begrænsede og forbudte pakker.

For en gennemgang af processen med at skrive en klasselæsser, inklusive prøvekode, se Chuck McManis's JavaWorld artikel, "Grundlæggende om Java-klasselæssere."

Næste måned

I næste måneds artikel fortsætter jeg diskussionen om JVM's sikkerhedsmodel ved at beskrive klasseværifikatoren.

Bill Venners har skrevet professionelt software i 12 år. Baseret i Silicon Valley leverer han softwarekonsulent- og træningstjenester under navnet Artima Software Company. Gennem årene har han udviklet software til forbrugerelektronik, uddannelse, halvleder og livsforsikringsindustri. Han har programmeret på mange sprog på mange platforme: monteringssprog på forskellige mikroprocessorer, C på Unix, C ++ på Windows, Java på nettet. Han er forfatter til bogen: Inside the Java Virtual Machine, udgivet af McGraw-Hill.

Lær mere om dette emne

  • Bogen Specifikationen for den virtuelle Java-maskine (//www.aw.com/cp/lindholm-yellin.html), af Tim Lindholm og Frank Yellin (ISBN 0-201-63452-X), en del af Java-serien (//www.aw.com/cp /javaseries.html), fra Addison-Wesley, er den definitive Java-virtuelle maskinreference.
  • Sikker databehandling med JavaNow og fremtiden (en hvidbog) // www.javasoft.com/marketing/collateral/security.html
  • Ofte stillede spørgsmål om applets sikkerhed

    //www.javasoft.com/sfaq/

  • Sikkerhed på lavt niveau i Java, af Frank Yellin //www.javasoft.com/sfaq/verifier.html
  • Hjemmesiden til Java-sikkerhed

    //www.javasoft.com/security/

  • Se den fjendtlige applets startside

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

  • Bogen Java-sikkerhedHostile-applets, huller og modgift, af Dr. Gary McGraw og Ed Felton, giver en grundig analyse af sikkerhedsspørgsmål omkring Java. //www.rstcorp.com/java-security.html
  • Tidligere artikler "Under hætte":
  • The Lean, Mean Virtual Machine - Giver en introduktion til den virtuelle Java-maskine.
  • Java Class File Lifestyle - Giver en oversigt over Java-klassefilen, det filformat, som alle Java-programmer er samlet i.
  • Java's Garbage- Collected Heap - Giver et overblik over affaldssamling generelt og den skraldesamlede bunke på Java-virtuelle maskine i særdeleshed.
  • Grundlæggende om Bytecode - Introducerer bytecodes på den virtuelle Java-maskine og diskuterer især primitive typer, konverteringsoperationer og stack-operationer.
  • Flydende punkts aritmetik - Beskriver den virtuelle Java-maskines understøttelse af flydepunkter og de bytekoder, der udfører operationer med flydende punkt.
  • Logik og aritmetik - Beskriver understøttelsen af ​​den virtuelle Java-maskine til logisk og heltal aritmetik og de relaterede bytekoder.
  • Objekter og arrays - Beskriver, hvordan den virtuelle Java-maskine håndterer objekter og arrays, og diskuterer de relevante bytekoder.
  • Undtagelser - Beskriver, hvordan den virtuelle Java-maskine håndterer undtagelser, og diskuterer de relevante bytekoder.
  • Prøv-Endelig - Beskriver, hvordan den virtuelle Java-maskine implementerer prøve-endelige klausuler, og diskuterer de relevante bytekoder.
  • Control Flow - Beskriver, hvordan den virtuelle Java-maskine implementerer kontrolflow og diskuterer de relevante bytekoder.
  • Arkitekturen af ​​aglets - Beskriver aglets indre funktion, IBMs autonome Java-baserede softwareagentteknologi.
  • Point of Aglets - Analyserer den virkelige verden af ​​mobile agenter som aglets, IBMs autonome Java-baserede softwareagentteknologi.
  • Metodeindkaldelse og tilbagevenden - Beskriver de fire måder, som den virtuelle Java-maskine påberåber metoder, herunder de relevante bytekoder.
  • Trådsynkronisering - Viser, hvordan trådsynkronisering fungerer i den virtuelle Java-maskine. Diskuterer bytekoderne til indtastning og afslutning af skærme.
  • Java's Security Architecture - Giver et overblik over sikkerhedsmodellen indbygget i JVM og ser på JVM's indbyggede sikkerhedsfunktioner.

Denne historie, "Sikkerhed og klasselæsserarkitekturen" blev oprindeligt udgivet af JavaWorld.