Szerző: Budai Péter

2004. január 29. 16:04

A szoftverek biztonságának kérdéseiről

Nyilvánvalóan nem lehet pár oldalban összefoglalni a szoftvereket érintő valamennyi biztonsági kérdést, azonban nem szabad elfelejteni, hogy a biztonságtechnikával való foglalkozás folyamatos versenyfutást jelent, amelyben lépést kell tudni tartani mind a támadókkal, mind az új védelmi technológiákkal.

Sokáig elégségesnek tűnt, hogy a számítógépek és a hálózatok biztonságát a hálózati kommunikáció irányából, a külső támadások kivédésével próbáltuk garantálni, azonban mára már érzékelhető, hogy ez önmagában kevés a biztonság eléréséhez. Mivel nem hihetjük azt, hogy a számítógépre telepített valamennyi szoftver hibátlan, és könnyedén kerülhet akár szándékosan hibás, illetve kártékony kód is a rendszerbe, ezért szükség van olyan infrastruktúrára, amely a szoftverek futását előre meghatározott irányelveknek megfelelően szabályozza.

Ez a probléma otthoni felhasználóknál, de akár több ezer számítógépből álló hálózatok rendszergazdáinál is felmerülhet, hiszen akár egyetlen vírusos program letöltésével és futtatásával kikerülhető a teljes hálózati biztonsági réteg, és attól fogva az operációs rendszer, illetve a kódot futtató réteg feladata az, hogy megakadályozza a kódot az általunk nem engedélyezett tevékenységek elvégzésében.

A számítógéprendszerek felépítésekor két alapvető dolgot kell figyelembe vennünk:

  • Bármely felhasználó vagy program okozhat kárt, akár szándékosan, akár véletlenül; ezt a kárt minimalizálni kell, illetve optimális esetben teljesen lehetetlenné kell tenni a kár keletkezését. (a realistább szemszögből nézve a kár létrejötte nem lehetőség, hanem egy előre ismert, mindenképpen bekövetkező esemény)
  • Minden felhasználó és program el kell, hogy érje azokat az erőforrásokat, amikre szüksége van az általunk jóváhagyott tevékenységek elvégzése során.
A jó rendszergazda képes mindkét igénynek együttesen megfelelni, vagy ha erre adott esetben nincs mód, akkor meg kell találnia a kettő közötti egyensúlyt.

A szoftverek biztonságával kapcsolatban még a programozóknak is vannak kívánságaik. Elsősorban szeretnék a lehető legkevesebb energia feláldozásával biztosítani, hogy a szoftverük hibátlan legyen, vagy legalább az esetlegesen előforduló hibák a lehető legkisebb kárt okozzák. Azok a fejlesztők, és cégek, akiktől idegen a nyílt forráskód koncepciója, még azt is nehezményezik, ha az elkészült programot valaki visszafejti, és saját céljaira felhasználja, esetleg jogtalanul visszaél egy cég vagy személy nevével, és például egy vírust javítócsomagnak álcáz ezáltal.

A felhasználók elvárásai általában egyszerűbbek, azonban hasonlóan nehezen valósíthatóak meg: ők csak használni szeretnék a számítógépüket, de úgy, hogy semmilyen kár ne keletkezhessen a gépükben, és mégis mindent kipróbálhassanak, használhassanak.

A következő oldalakon sorra vesszük azokat a lehetőségeket és megoldásokat, amik kombinálásával növelhető a szoftverek biztonsága.

[oldal:Elterjedtebb megoldások]

A legalapvetőbb megoldásokat szinte minden számítógéppel foglalkozó ember ismeri, ezek jelenleg a számítógéprendszerek szoftveres védőbástyái. Ezek a technológiák még bizonyos körülmények között könnyedén megkerülhetőek, azonban használatuk elengedhetetlen.

Az alapmegoldások többsége tüneti kezelés. Egy vírusra csak azután lehet érdemben reagálni, ha már találkoztak vele; a heurisztikus megoldások nem bizonyultak megfelelően hatékonynak. A felhasználók csak reménykedhetnek, hogy előbb jut el hozzájuk a legújabb vírusdefiníciós fájl, mint maga a vírus. Ugyanez igaz a szoftverek hibáira is: ha egy szoftver, vagy egy kommunikációs protokoll feltörhető, és azon keresztül kár okozható, akkor az erre a hibára kiadott biztonsági frissítés nem biztos, hogy időben érkezik.

A frissítések automatizált, szinte azonnali letöltésére már minden operációs rendszerben van lehetőség, amit kellő jóindulattal akár megelőző kezelésnek is nevezhetnénk, azonban ezek mind a jelenlegi számítógépek és szoftverek tervezésének hibáit használják ki: nincs egységes, és megfelelően működő biztonsági réteg a futó szoftverek, és a hardverelemek között. Nem lehet minden hibára előre felkészíteni a mai PC-ket és operációs rendszereket, kizárólag arra van lehetőség, hogy a már ismertté vált hibák, biztonsági rések utólag befoltozásra kerüljenek.

Még mindig elterjedt megoldás a felhasználóra bízni, hogy futtat-e egy adott programot, vagy sem. Bármikor előfordulhat, hogy egy felhasználó véletlenül rossz gombra kattint, vagy éppen nem tudja eldönteni, hogy egy fájl ártalmas-e. Ilyenkor egy kéretlen szoftver gond nélkül megfertőzheti a számítógépet. Az se a legjobb megoldás, ha szisztematikusan megtiltják a felhasználóknak, hogy bármit is letöltsenek, ami ismeretlen eredetű, vagy éppen csak gyanús. Márpedig ezekkel a problémákkal nap, mint nap találkozunk e-mailek csatolt fájljai, letöltött fájlok, ActiveX-ek és scriptek kapcsán.

A tanúsítványok használata volt az első komolyabb lépés az internetről áradó információ biztonságosságának biztosítása felé. Egy CA (Certificate Authority, Tanúsítvány-kiállító és -felügyelő) által kibocsátott tanúsítvány segítségével egyértelműen azonosíthatóak a vele ellátott fájlok, ezáltal pontosan meg lehet állapítani, hogy egy adott állomány általunk ismert cégtől, személytől, vagy egy ismeretlen, potenciálisan veszélyes forrástól származik. A tanúsítványok használata védi a fejlesztőket is, mert a szoftver valódiságáról, eredetéről, fejlesztőiről mindenki meggyőződhet a fájlok alapján. Az állományok módosítása, feltörése esetén érvénytelenné válik a hozzáfűzött tanúsítvány, ezért egy tanúsított állomány biztosan azt a szoftvert tartalmazza, amit az adott cég, vagy személy el akart hozzánk juttatni.

Ezzel a megoldással már automatizálható, hogy egy adott felhasználó gond nélkül használhassa az általánosan elismert cégek szoftvereit, vagy a személyes ismerősöktől érkező kódokat, de ez sem véd tökéletesen, ugyanis semmi sem garantálja, hogy az általunk megbízhatónak ítélt partnerek nem küldenek szándékosan, vagy akaratukon kívül veszélyes szoftvereket a felhasználókhoz. Ha egy szoftverről elhisszük, hogy megbízható, és a vírusellenőrző is átengedi, majd lefuttatjuk, akkor már gyakorlatilag nincs ellenőrzésünk afölött, hogy mi történik a rendszerben a továbbiakban. Az adott szoftver a bejelentkezett felhasználó jogosultságaival gond nélkül visszaélhet (hacsak nem futtatjuk egy másik felhasználó segítségével).


Egy tanúsítvány adatai

A közelmúltban egyre többen részesítik előnyben a valódi megelőzést. Találkozhattunk már olyan kernelekkel, amelyek azt ígérték, hogy a puffertúlcsordulást az esetek nagy részében nem engedélyezik. Most már a hardverek szintjén is jelennek meg ilyen jellegű megoldások, gondoljunk csak az AMD és az Intel új processzoraira, amelyek már támogatják az "Execution Protecion" kódnéven emlegetett technológiát is. A puffertúlcsordulás kihasználása igen népszerű betörési mód, amivel elérhető, hogy a processzor olyan parancsokat futtasson le, amiket a rosszindulatú szoftverek juttatnak be a memóriába. A biztonsági rések száma az ilyen hardveres megoldások elterjedésével jelentősen csökkenni fog, azonban ez csak egy hosszabb távú folyamat eredményeképpen képzelhető el, és még ez sem jelent elégséges védelmet valamennyi kártékony szoftver ellen.

[oldal:Keretrendszerek (Java, .Net)]

Mivel a legjelentősebb biztonsági probléma továbbra is az, hogy a processzor bármilyen kódot azonnal, gondolkodás nélkül lefuttat, ezért azok a programozási keretrendszerek, amelyek a szoftverek lefuttatásakor értelmezik, és a processzor által értelmezhető formába öntik a kódot, még tehetnek az ellen, hogy a nem engedélyezett parancsok végrehajtódjanak. Ennek hatékony alkalmazása azonban a szoftverfejlesztési módszerek megváltoztatásával, és új eszközök használatának megkövetelésével jár. A Java keretrendszere csak a Java programozási nyelv használatával érhető el, a .Net keretrendszerre azonban szinte valamennyi modern programozási nyelv segítségével lehet fejleszteni.

A jelenleg elterjedt keretrendszerek további hasznos tulajdonsága, hogy nagyrészt mentesíti a programozókat a legtöbb hibát és nyűgöt okozó memóriakezelés alól, ezért a puffer-problémák már szinte nem is fordulhatnak elő. A memóriakezelést Garbage Collector (szemétgyűjtő) alkalmazásával teszik hatékonyabbá, ami a létrehozott objektumokat automatikusan kitörli a memóriából, ha már nincsen rájuk élő hivatkozás - vagyis ha a memóriaterületet senki sem használja. Ugyancsak előny, hogy nem a fejlesztő feladata a rendszer memóriájának lefoglalása sem, ezt minden objektum létrehozásakor a keretrendszer végzi el.

A modern programozási nyelvek mindegyike támogatja a kivételkezelést, ami lehetőséget teremt arra, hogy egy, a program futása során előforduló hibát ott kezeljünk le, ahol minden szükséges információ rendelkezésre áll róla. Ennek segítségével hatékony, hibatűrő szoftverek építhetőek. Ha a program egy résztevékenységén belül keletkezik kivétel, és ott nem számítunk rá, vagy nem kezeljük le, akkor a kivétel leírására szolgáló összes információ továbbkerül a résztevékenységet kezdeményező programrészhez. Amennyiben egy kivétel elérkezik az operációs rendszerhez, vagyis a program sehol nincs felkészítve egy adott kivétel előfordulására, akkor jó esély van rá, hogy a szoftver hibaüzenettel leáll.

A keretrendszerek bevezetik a Code Security (Kódbiztonság) fogalmát is. Használatával a forráskódban megadhatjuk, az operációs rendszerben pedig finomhangolhatjuk, hogy adott parancsok lefutásához milyen jogosultságokat követeljen meg a program, és azt is, hogy adott parancs lefutását pontosan milyen jogosultságokkal végezze el a keretrendszer. A jogosultság lehet egy erőforrás elérése, de akár egy adott felhasználói csoportba tartozás ténye is. A jogosultság meglétét a keretrendszerek a teljes parancsfán (call stack) ellenőrízhetik, ilyen esetekben a parancsot meghívó összes korábbi parancsnak is rendelkeznie kell a kellő jogosultságokkal.

Az első esetben például, ha nincs az adott felhasználónak joga írnia a C meghajtóra, akkor kívánságunkra a keretrendszer minden olyan parancs meghívásakor kivételt generál, amik írási jogot kérnek a C meghajtóra, és sikertelenül végződnek.

A második esetben minden parancsra beállíthatjuk, hogy mi az a legkevesebb jog, amire feltétlenül szüksége van a sikeres lefutáshoz, és ha azt megkapja, sikeresen le is fut. Ha azonban több jogot kap, mint amire szüksége van, akkor a számára nem szükséges jogokat nem engedélyezi a parancs lefutásakor. Ezt úgy lehet elképzelni, hogy ha a parancsunk azt állítja, hogy nincs szüksége a fájlrendszerre írás jogára, és mégis megkapja, akkor sem lehet a meghívott parancson keresztül a fájlrendszerre írási műveletet végezni. Ez a koncepció szakít a fejlesztés korábbi hagyományaival, és elvárja a programozóktól, hogy pontosan végiggondolják, milyen kód fog lefutni az alkalmazásuk adott részegységeiben, és milyen erőforrásokat fognak elérni a metódusaikon keresztül.

Az, hogy kinek mire van joga, a keretrendszerek konfigurációs alkalmazásaival állítható be. Itt lehetőség van felhasználók, csoportok és számítógépek szintjén, valamint globálisan is megadni, hogy kinek milyen jogai vannak a rendszer egészére nézve, majd ezeket akár regisztrált alkalmazásonként is külön testre lehet szabni. Ez nagyban hasonlít a hálózati operációs rendszerek felhasználói jogosultságkezeléséhez.


A .Net keretrendszer konfigurációs ablaka

A Microsoft által létrehozott keretrendszer lehetőséget nyújt a már meglévő, nem .Net alapú kód és a .Net-es kód ötvözésére is, azonban ilyen esetekben a biztonság teljes körűen nem garantálható. Ha a vezérlés átkerül a nem .Net alapú kód irányítása alá, akkor ugyanazokkal a gyerekbetegségekkel kell szembesülni, amik a jelenlegi fejlesztési folyamatot is jellemzik. Erre két esetben van szükség: ha már meglévő, nem .Netre épülő API-kat akarunk elérni .Net-en keresztül, és ha korábban kifejlesztett programrészeket szeretnénk újrahasználni, a kód újraírása nélkül.

Mind a Java, mind a .Net visszafejthető kódot hoz létre, ezért különösen fontos, hogy a fejlesztők megvédhessék szellemi tulajdonukat, illetve megakadályozzák azok illetéktelen módosítását. Erre a célra születtek az obfuscatorok (összezavaró), amik az elkészült kódot olyan módon alakítják át, hogy a működése semmilyen szempontból se változzon meg, de a változók neveit, és a futás szempontjából lényegtelen összetevőket olyan mélységig zavarják össze, hogy a visszafejtőnek komoly nehézségekkel kelljen szembenéznie. A keretrendszerekkel létrehozott kódokat szintén digitális aláírással, illetve tanúsítványokkal lehet azonosítani, védeni.

Ezek a technikák mind a programozási hibák, mind a kártékony vírusok és szoftveres behatolások számát jelentősen csökkenteni fogják. Viszont a gond ezzel a megoldással az, hogy csak azokra a programokra alkalmazható, amelyek a keretrendszerekre készültek, ezért jelenleg csak akkor nyújt igazi biztonságot, ha a keretrendszeren kívül írt programok futását csak nagyon szigorú feltételek mellett, vagy egyáltalán nem engedélyezzük. A jelenlegi megoldások nem is a szoftveres biztonsági architektúra azonnali megváltására készültek, sokkal inkább az új technikára történő rászoktatásról van szó; teljes hálózatok átalakítására nem alkalmasak, sem otthoni felhasználók rendszereinek megreformálására. Zárt, üzleti, nagyvállalati rendszerek esetében azonban már el lehet gondolkodni a használatán.

Hosszabb távon, a szoftverek és operációs rendszerek körültekintő újratervezése során, ha figyelembe veszik a keretrendszerek által felajánlott szolgáltatásokat, lehetőség nyílik sokkal biztonságosabb rendszerek kialakítására, akár otthoni felhasználók számára is. Várhatóan ez történik most a Longhorn esetében, ahol már a rendszer jelentős része - beleértve a kernel egyes részeit, és az összes API-t is - a .Net keretrendszerre épül.

[oldal:Kódolás, kommunikáció]

Mindkét keretrendszer, valamint a legtöbb függvénykönyvtár rendelkezik kódolásra-dekódolásra és azonosításra alkalmas szolgáltatásokkal. Ezekre különösen adatok tárolásakor és szállításakor lehet szükség, amikor értékes információk kerülnek ki a szoftver irányítása alól, és ezzel együtt a memóriából, valamint a keretrendszerek védelme alól. Íme a legfontosabbak:

  • Szimmetrikus kódolás. Elve, hogy a kódolás és a dekódolás ugyanazzal a kulccsal hajtódik végre. Pl. DES, RC2.
  • Asszimmetrikus kódolás. Itt a szimmetrikussal kódolással ellentétben a kódoláshoz és a dekódoláshoz használt kulcs nem egyezik meg. Pl. RSA, DSA.
  • Hash-számítás. A Hash algoritmusok eredménye egy olyan egyedi érték, ami szinte teljes biztonsággal eltérő minden egymástól különböző adathalmaz esetén. Általános felhasználási területe az azonosítás. Előnye, hogy ugyanaz az adathalmaz mindig ugyanazzal a hash-kóddal rendelkezik, és mégse lehet ebből a hash értékéből következteni az eredeti adathalmaz tartalmára. Pl. SHA1, MD5.

Ezek a szolgáltatások a .Net keretrendszer szerves részét képezik, de akár API-kon kereszül is elérhető Windows vagy Linux alatt. A Java 2 SDK 1.4 előtti verzióihoz a JCE (Java Cryptography Extension) csak opcionális kiegészítésként létezett. A legújabb kiadások már tartalmazzák a kódolással foglalkozó osztályokat.

A szoftverek közötti kommunikáció is fontos része a biztonsági architektúráknak. Eddig is rengeteg lehetőség volt alkalmazások és távoli gépeken futó szolgáltatások közötti kommunikációra, azonban ezeknek a megoldásoknak a sokszínűsége miatt egyre több problémával szembesülnek az informatikusok. Nagyon komoly feladatot jelent két teljesen eltérő kommunikációs protokollal beszélgető alkalmazás integrálása, márpedig jelenleg szinte minden cég olyan szoftvereket szeretne létrehozni, amely bármely másik - akár már létező, akár még ki sem fejlesztett - szolgáltatással képes együttműködni. Ezen kívül a különféle, gyakran egyetlen programozó által készített kommunikációs protokolok nem garantálhatnak tökéletes biztonságot sem.

A cél ezért olyan szabványos, egységes technikák létrehozása, amelyek lehetővé teszik heterogén környezetben futó alkalmazások kommunikációját. Ez volt az oka az XML alapú WebService-ek (web alapú szolgáltatások) elterjedésének, ami a következő, általánosan elismert szabványokra épül:

  • Extensible Markup Language (XML): Leíró nyelv, amely adatok szabványos tárolására nyújt lehetőséget egyetlen szöveges állományban.
  • Simple Object Access Protocol (SOAP): Általános kommunikációs módszer, amivel megadható, hogy egy adott szoftverbe beérkező adatokkal mi és hogyan történjen, illetve milyen visszatérő paraméterekre számít a kérést küldő alkalmazás.
  • Universal Discovery Description and Integration (UDDI): Az interneten megtalálható WebService-ek közötti keresésre, és saját alkalmazások interneten történő regisztrálására ad felületet.
  • Web Service Description Language (WSDL): A WebService-ek ennek segítségével írhatják le, hogy milyen működésre képesek, milyen tevékenységeket tudnak elvégezni, illetve milyen paramétereket fogadnak és adnak vissza. Felhasználásával könnyedén írható olyan alkalmazás, ami az adott WebService képeségeit aknázza ki, anélkül, hogy ismernénk annak belső felépítését, algoritmusait, vagy dokumentációját.

Az XML WebService-ek elterjedésével egyre sürgetőbbé vált a biztonság és a megbízhatóság egységes módon történő garantálása a szabványos protokolokon keresztül. A WS-Security elnevezésű projekt - aminek életrehívói az IBM, a Microsoft és a VeriSign - 2002 áprilisában kezdődött meg. Célja olyan SOAP-alapú fejlécek definiálása, amelyek képesek megfelelni az újonnan felmerült igényeknek. Ennek az együttműködésnek az eredményeképpen a következő szabványok születtek, amik mind a WS-Security által lefektetett alapokra épülnek:

  • WS-Policy, WS-Trust, WS-Privacy: Leírják a jogosultságkezelési rendszer struktúráját, használati módját, illetve két WebService közötti biztonságos kapcsolat létrehozására adnak lehetőséget.
  • WS-Secure Conversation, WS-Federation, WS-Authorization: A biztonságos üzenetküldéssel, kommunikációval, heterogén környezetekben történő jogosultságkezeléssel, és beléptetéssel foglalkozó specifikációk.

Ezek a szabványok még nem kerültek elfogadásra, de kezdeti változataik már elérhetőek, véleményezhetőek, és akár használhatóak is - bár ezzel érdemesebb megvárni a specifikációk végleges állapotát.

[oldal:Zárszó]

Ez a cikk bevallottan gondolatébresztés céljával készült. Nyilvánvalóan nem lehet pár oldalban összefoglalni a szoftvereket érintő valamennyi biztonsági kérdést, azonban nem szabad elfelejteni, hogy a biztonságtechnikával való foglalkozás folyamatos versenyfutást jelent, amelyben lépést kell tudni tartani mind a támadókkal, mind az új védelmi technológiákkal.

Várhatóan egy hosszabb folyamat eredményeképpen a jövő számítógépeinek és szoftvereinek olyan felépítése lesz, amely a legtöbb biztonsági kérdést automatikusan megoldja, és ezáltal ismét a produktivitásra fog kerülni a hangsúly, csakúgy, mint a számítógépek fejlődésének első évtizedeiben. Viszont ez az átállás nagy nehézségeket fog jelenteni, különösen a kompatibilitás megőrzése és a megszokott módszerekhez való ragaszkodás miatt. Komoly erőfeszítést, és időt fog igényelni a régebbi programozási nyelveken fejlesztők számára átállni a Java, vagy .Net használatára, és még az ezeken a keretrendszereken programozóknak is folyamatosan szem előtt kell tartaniuk a biztonságos programozás alapkérdéseit. A Java és a .Net használatára az operációs rendszereket is fel kell készíteni, mivel a régebbi operációs rendszerek többsége alapbeállítások mellett egyiket sem támogatja. Természetesen a folyamat hossza miatt elképzelhető, hogy pár év múlva már nem ezek a programozási keretrendszerek, és a rájuk épülő operációs rendszerek fogják nyújtani a legjobb megoldást, hanem példának okáért a hardverek lesznek felelősek az alacsonyszintű biztonsági kérdésekért, és a szoftverek csak konfigurációs felületet fognak nyújtani ezekhez a szolgáltatásokhoz. Ebben az esetben ismét csak egy lehetősége van a témával foglalkozóknak: a folyamatos fejlődés, lépéstartás a legújabb technológiákkal.

Mivel a Longhorn, és az erre épülő későbbi operációs rendszerek API-jai is nagyrészt a .Net keretrendszer szolgáltatásaira épülnek, ezért ahhoz, hogy a szoftvereinket mindenki bizalommal használja majd, meg kell felelnünk a jövő programozási keretrendszereinek is. Mindazok a szoftverek, amik nem Java, vagy .Net alatt, keretrendszerre építve készülnek, potenciális veszélyforrást fognak jelenteni mindaddig, amíg nem születik jobb megoldás a biztonsági problémák általános kezelésére. Linux alatt még kérdéses, hogy a Javának hosszabb távon milyen alternatívái lesznek, viszont a Mono, a .Net Linuxos portolásával foglalkozó project nagyon ígéretes eredményeket mutatott fel eddig, ezért úgy tűnik, hogy bármely platformon lehetőség lesz választani a .Net és a Java között.

A szoftverek közötti kommunikáció miatt is ajánlott elismert szabványok szerint fejleszteni alkalmazásainkat. A legjobb választásnak most a platformfüggetlen XML WebService-ek tűnnek, mert egyetlen módszer megismerésével szinte bármelyik operációs rendszerre és tetszőleges programozási nyelven elkészíthetjük szolgáltatásainkat, amikkel más fejlesztők alkalmazásai is képesek lesznek együttműködni. Ha ez nem cél, akkor a keretrendszerek saját kommunikációs megoldásait is érdemes használni, de az így kapott szoftverek nem lesznek túl rugalmasak, ha később bővítésre kerül sor.

Várhatóan a vállalati szoftverek területén fog először elterjedni a biztonságos programozás alkalmazása, mert rövidtávon csak itt lehetséges áttörni a megszokások falán, és megkövetelni újabb biztonsági intézkedéseket. Az otthoni, és irodai felhasználók által használt összes szoftvert lehetetlen rövid idő alatt átalakítani az új biztonsági elvárásoknak megfelelően.

Szólj hozzá a fórumban!

Nagyon széles az a skála, amin az állásinterjú visszajelzések tartalmi minősége mozog: túl rövid, túl hosszú, semmitmondó, értelmetlen vagy semmi. A friss heti kraftie hírlevélben ezt jártuk körül. Ha tetszett a cikk, iratkozz fel, és minden héten elküldjük emailben a legfrissebbet!

a címlapról