Bezpečnost software .NET Framework .
Transkript
Bezpečnost software .NET Framework .
Bezpečnost software .NET Framework . Cílem tohoto tutoriálu bude seznámit čtenáře ze základy zabezpečení u projektů na bázi .NET Framework. Na základě připomínek jsem tento tutoriál rozšířil. Je nutno si uvědomit, že k pochopení zabezpečení v celém rozsahu musíte zvládnout přidělování a uvolňování paměti, práce se zásobníkem a případně API-PInvoke. V tomto článku jsem neřešil zabezpečení pro IIS aplikace a mobilní aplikace. Pokud vytvoříme nějaký projekt budeme požadovat, aby náš software pracoval na různých počítačích nebo na webovém serveru. Nemá být náchylný ke změnám od různých uživatelů a neměl by ovlivňovat stávající operační systém na kterém bude nainstalován. Bezpečnost se dříve nejčastěji řešila na základě zjišťování identity uživatele. Veškeré operace byly kontrolovány podle práv, která přidělil administrátor. Takto řešený systém již nevyhovuje. Pokud se podíváme do nedaleké minulosti začátek nové éry zavedl Microsoft Transaction Server, který založil systém bezpečnosti na rolích. Role sdružují uživatele nezávisle na tom, v jakých systémových skupinách se nacházejí. Tento princip převzal .NET Framework a ještě ho rozšířil. Bezpečnost na platformě .NET se dotýká těchto oblastí. Typová bezpečnost – programy pracují pouze s pamětí, která byla alokována pro jejich objekty. Na příklad třída, která je typově bezpečná neumožní přistupovat k soukromým členům třídy žádným způsobem. Přístup je garantován pouze přes její definované rozhraní. Přístupové bezpečnosti kódu - tento typ bezpečnosti umožňuje nastavit důvěryhodnost kódu v závislosti na tom, odkud kód pochází a dalších aspektech identity kódu. Můžeme nastavit, které operace s danou identitou může vykonávat a které nikoliv. Identity kódu – tuto zabezpečují služby, které zavádějí aplikaci do paměti. Informace o vydavateli, místě ze kterého kód pochází a podobně. Deklarativního a imperativního řízení bezpečnosti – v další části se budeme zabývat podrobněji. Povolení – CLR umožňuje vykonávat pouze operace, na které má kód povolení. Zde se rozlišují dva typy povolení: o Povolení pro přístup ke kódu – základní nástroj (přístup k chráněným systémovým zdrojům a práva pro spuštěných chráněných operací, volání funkcí neřízeného kódu a podobně) o Povolení identity Bezpečnosti založené na rolích – využívá objekt Principal, v další části se budeme zabývat podrobněji. Kryptografických služeb – sada kryptografických objektů, šifrovací algoritmy, hashovací funkce. Zde mi dovolte malé odbočení, pro oživení vaší paměti. Problémem při nasazování aplikací v prostředí .NET vyřešilo zavedení Assembly. Důvodů zavedení bylo několik: Aplikace musí být samostatné – snadná instalace nebo reinstalace. Aplikace musí obsahovat čísla verzí a musí být na ně vázána. Čísla verzí komponent – vedle vlastní verze si musí aplikace pamatovat čísla verzí komponent, které interně používá. Musí podporovat Side-by-side komponenty – existence dvou a více verzí stejné komponenty na jednom počítači je realitou a jedním z velkých problémů současných instalací. Musí umožňovat izolaci aplikace – aplikace nesmí být náchylná k poruchám způsobených změnami provedenými na počítači. Musí zajistit bezpečný přístup ke kódu. Komponenty musí obsahovat informace o veřejných typech. Co je assembly? Assembly je logickou kolekcí, stávající se z jednoho nebo více .exe, .dll nebo .module souboru a zdrojů doplněných o manifest. Assembly je také často definována jako programová jednotka určená k nasazení a opakovanému použití, řízení verzí a bezpečnosti. Assembly je velice podobná dnešní dynamicky linkované knihovně, jsou však na ní kladeny vyšší požadavky. Tyto vyšší požadavky jsou splněny přidáním tzv. manifestu do Assembly. Stránka 1 Manifest je blok metadat obsahující tyto informace: identita – jméno, verze a kultura; seznam souborů + kryptografické zabezpečení; odkaz na další použité assembly + jejich verze; exportované (veřejně viditelné) typy a zdroje; bezpečnostní požadavky. V průběhu času se měnilo zabezpečení u .NET Framework, zlom nastal při nasazení verze 4.0 a vyšší. Microsoft rozděluje .NET Framework na dva různé typy zabezpečení (Rozdíl Level1 a Level2 MSDN), na zabezpečení SecurityRuleSet.Level1 a SecurityRuleSet.Level2. My se budeme v tomto článku zabývat SecurityRuleSet.Level2, to znamená zabezpečením platícím od .NET Framework verze 4.0 a vyšším. Zaměřím se na praktické ukázky kódu. Ve všech ukázkách bude doplněno AssemblyInfo.cs o tento kód: using Systém; using System.Security; [assembly: SecurityRules(SecurityRuleSet.Level2)] //1 [assembly: CLSCompliant(true)] //2 1. Budeme používat .NET Framework minimálně verze 4.0 2. Veškerý kód, který bude generován kompilátorem, bude možno používat i u jiných jazyků na příklad Linuxu a podobně. Bližší popis v MSDN. Pro pochopení uvedu definice názvů, které jsou v této ukázce použity: Attributy – jsou zvláštní údaje o entitách v kódu (třídách, metodách, vlastnostech a podobně), které se do zdrojového kódu vkládají pomocí speciální syntaxe. Attributy mohou měnit chování těchto entit, nebo mohou být uloženy jako dodatečné kusy metadat v kompletech. (konec citátu z knihy Visual C++ .NET). Attributy jsou začleněny do programu v době kompilace. Atributy jsou přístupné pomocí reflexe. Pokud uplatníme oprávnění pomocí atributů, nelze zachycovat žádné výjimky v případě selhání. ( nemůžeme nikam umístit try-catch-finally ). Transparentní kód – může volat jiný transparentní kód nebo částečně důvěryhodný kód. Může provádět pouze akce povolené částečně důvěryhodnou sadou oprávnění náležící doméně. Existuje několik omezení uvalená na transparentní kód. Zejména tento kód nemůže provádět: 1. Volat SecurityCricital kód, ale může volat také SecuritySafeCritical kód. 2. Provádět metodu Assert nebo zvyšovat úroveň oprávnění. 3. Obsahovat nebezpečný (unsafe) nebo neověřitelný (unverifiable) kód. 4. Nelze volat P/Invoke metody. 5. Přepsat nebo dědit kritické typy a metody. 6. Volat člen, který je chráněn pomocí LinkDemand. Částečně důvěryhodný kód je v .NET Framework 4 a výše, předefinován jako transparentní kód. Transparentní model kreslí bariéru mezi kódem, který může dělat privilegované věci (kritický kód), jako je například volání nativního kódu a kódem, který tyto věci dělat nemůže (transparentní kód). Transparentnost vylučuje použití LinkDemand k identifikaci plně důvěryhodného kódu a ovlivňuje pravidla pro spuštění částečně důvěryhodného kódu. (MSDN) Kritický kód je malá část zdrojového kódu, kde dochází k přístupu ke sdílenému prostředku (např. sdílená data, která označujeme jako kritická oblast), ke kterému nemohou současně přistupovat dva nebo více procesů či vláken. Programy, které usilují o vstup do kritické sekce, musí použít nějaké synchronizační primitivum, které má za úkol zajistit do kritické sekce exkluzivní přístup a zároveň konečnou dobu čekání na povolení ke vstupu. Stránka 2 Používání atributů [SecurityTransparent], [SecuritySafeCritical] a [SecuritySafeCritical] Použití na úrovni sestavy (AssemblyInfo.cs) 1. Žádný atribut - všechny typy a členové tříd jsou transparentní, ale mohou být také kritické nebo SecuritySafeCritical mimo případů, kdy je porušeno pravidlo dědičnosti. 2. [assembly: SecurityTransparent] - všechny typy a členové jsou transparentní. Lze použít pouze v AssemblyInfo.cs. 3. [assembly : SecurityCritical] – všechen kód v této sestavě je kritický. Pokud přepíšeme virtuální nebo abstraktní metodu nebo implementujeme metodu rozhraní, pak musíme explicitně okomentovat metodu jako [SecurityCritical] nebo [SecuritySafeCritical]. 4. [assembly: SecuritySafeCritical] – nelze použít. Přepis vzorů pro interface a virtual. Base virtual/interface member Override/interface Transparent Transparent Transparent SafeCritical SafeCritical Transparent SafeCritical SafeCritical Critical Critical Pravidla dědičnosti. Pravidla dědičnosti musí být implementována v tomto pořadí: Transparent < SafeCritical < Critical V tabulce jsou uvedeny povolené typy dědičnosti. Základní třída Odvozená třída může být Transparent Transparent Transparent SafeCritical Transparent Critical SafeCritical SafeCritical SafeCritical Critical Critical Critical Stránka 3 Základní metoda Odvozená metoda může být Transparent Transparent Transparent SafeCritical SafeCritical Transparent SafeCritical SafeCritical Critical Critical Na příkladu si ukážeme použití kritického kódu: Tento příklad ukáže jak je řešena funkce FileStream(…) ze jmeného prostoru Systém.IO. Základem je API funkc SetFilePointer(…), která přemísťuje ukazatel pozice v souboru. Tento ukazatel indikuje, kde se v souboru provede čtení nebo zápis. Pokud pracujeme v aplikacích s násobným přístupem (multithread aplikace) musíme být při nastavování opatrní. Cesta zpracování zpráv sdílí stejné handle, a aktualizuje ukazatel souboru, musí být tato sekvence chráněna použití objektu kritické sekce nebo objektu mutexu. Tento příklad ukazuje jak přejít z kritického kódu na transparentní kód. [SecurityCritical] [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] private static extern unsafe uint SetFilePointer( [In] SafeFileHandle hFile, [In] int lDistanceToMove, [Out] int* lpDistanceToMoveHigh, [In] EMoveMethod dwMoveMethod ); Voláme API funkci (nebezpečný kód použití pointru) [SecurityCritical] internal static unsafe long SetFilePointer(SafeFileHandle handle, long offset, SeekOrigin origin, out int hr) { hr = 0; int lo = (int) offset; int num1 = (int) (offset >> 32); int num2 = UnsafeNativeMethods.SetFilePointerWin32(handle, lo, &num1, (int) origin); if (num2 == -1 && (hr = Marshal.GetLastWin32Error()) != 0) return -1L; else return (long) (uint) num1 << 32 | (long) (uint) num2; } Zde vidíme přechod mezi kritickým a transparentním kódem. //zde vidíme přechod mezi kritickým a transparentním kódem //using Systém.IO.FileStream [SecuritySafeCritical] private long SeekCore(long offset, SeekOrigin origin) { Stránka 4 int hr = 0; long num = Win32Native.SetFilePointer(this._handle, offset, origin, out hr); //nějaký kód } Transparentní kód. //using Systém.IO [SecuritySafeCritical] [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] public FileStream(SafeFileHandle handle, FileAccess access, int bufferSize, bool isAsync) { //nějaký kód this.SeekCore(0L, SeekOrigin.Current); //nějaký kód } Bezpečnostní koncepty můžeme rozdělit na dvě rozdílné skupiny: 1. Role Based Security Role jsou často používány ve finančních a obchodních aplikacích. Například, aplikace může stanovit omezení velikosti transakce zpracovávání v závislosti na tom, zda uživatel, je členem zadané úlohy. Úředníci mohou mít povolení ke zpracování transakce, které jsou menší než stanovený práh, orgány dohledu mohou mít vyšší limit, a místopředsedů by mohla mít ještě vyšší limit (nebo bez omezení vůbec). Zabezpečení založené na rolích lze použít také pro aplikace, které vyžadují několik povolení k provedení akce. Takovým případem by mohl být nákupní systém, ve kterém každý zaměstnanec může generovat požadavek na nákup, ale jen nákupčí jej může provést. Pro zajištění snadného používání a souladu se zabezpečením přístupu ke kódu .NET Framework umožňuje zabezpečení založené na rolích, realizované objekty v System.Security.Principal, které umožňují společnému jazykovému modulu runtime provést autorizaci způsobem, který je podobný bezpečnostním kontrolám přístupového kódu. PrincipalPermission je třída představující identitu nebo roli a je kompatibilní jak s deklarativními a bezpečnostními kontrolami. Existují dva způsoby, jak vytvořit WindowsPrincipal objekt, v závislosti na tom, zda kód musí opakovaně provádět ověřování na základě rolí, nebo kód ověřuje pouze jednou. WindowsPrincipal umožňuje zkontrolovat členství ve skupině Windows pro uživatele a provést kontrolu kódu. Tento příklad ukazuje, část třídy, kterou může spustit pouze uživatel, který má práva administrátora. using System; using System.Security.Permissions; using System.Security.Principal; using System.Security; class TestSecurityPrincipal { public static void Main() { /* Před k volání CurrentDemand metodu, je nezbytné stanovit hlavní zásady pro aktuální doménu aplikace hodnotu výčtu WindowsPrincipal. Ve výchozím nastavení hlavních zásad UnauthenticatedPrincipal. Pokud hlavní zásady není nastaven na WindowsPrincipal, na hlavní oprávnění vyžádaného volání se nezdaří. */ AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal); Stránka 5 //hodnota null – bude platit u windows pro skupinu administrátorů na libovolném PC PrincipalPermission principalPerm = new PrincipalPermission(null, "administrators"); try { principalPerm.Demand(); Console.WriteLine("Žádost o spuštění uspěla."); } catch(SecurityException ex) { Console.WriteLine("Žádost o spuštění neuspěla - " + ex.Message); } finally { Console.ReadLine(); } } 2. Zabezpečení přístupu ke kódu. Common Language Runtime (CLR) umožňuje kód provádět pouze ty operace, na které má kód oprávnění k provedení. Bezpečnostní systém CLR vynucuje bezpečnostní politiky tím, že zabraňuje neoprávněnému přístupu k chráněným zdrojům a operacím. Použitím zabezpečení přístupu ke kódu, můžeme provádět následující: Omezit, co váš kód může dělat Omezení, které kód může volat cizí kód Identifikovat kód Zabezpečení přístupu ke kódu se skládá z těchto prvků: oprávnění sady oprávnění skupiny kód důkaz politika Oprávnění: Oprávnění představuje přístup ke chráněným zdrojům nebo schopnost provádět chráněné operace. NET Framework poskytuje několik tříd oprávnění, na příklad FileIOPermission (při práci se soubory), UIPermission (povolení k použití uživatelského rozhraní), SecurityPermission (Definuje obor názvů tříd, které řídí přístup na operace a prostředky na základě zásad.) Sady oprávnění: Sada oprávnění je sbírka oprávnění. Můžeme si dát FileIOPermission a UIPermission do svého vlastní oprávnění souboru a říkat " MyPermissionSet ". Sada oprávnění může obsahovat libovolný počet oprávnění, na příklad FullTrust, LocalIntranet, Internet, Execution a Nothing a jsou v sadě oprávnění v rozhraní .NET Framework. FullTrust má všechna oprávnění na světě, zatímco Nothing nemá vůbec žádné oprávnění. Stránka 6 Kódové skupiny: Skupina Code je logické seskupení kódu, který má nastavenou podmínkou pro členství. Kód z webové stránky může patřit do jedné kódové skupiny, kód obsahující specifický silný název může patřit do jiné kódové skupiny a kód z konkrétní sestavy může patřit do jiné kódové skupiny. Tyto jsou vestavěné ve skupinách kódu jako My_Computer_Zone , LocalIntranet_Zone , Internet_Zone atd. Stejně jako sady oprávnění, můžeme vytvářet skupiny kde kód bude plnit naše požadavky na základě důkazů předložených .NET Framework. Site , Strong Name , Zone a URL toto jsou některé typy důkazů zde ukázaných. Politika: Bezpečnostní politika je konfigurovatelný soubor pravidel, která CLR sleduje při stanovení oprávnění udělit kódu. K dispozici jsou čtyři úrovně politiky - Enterprise , Machine , User a ApplicationDomain, každá pracuje nezávisle na sobě. Každá úroveň má své vlastní skupiny kódů a sady oprávnění. (Viz obr. použit z MSDN) Pro kódování můžeme použít dva druhy kódování (deklarativní a imperativní). Deklarativního zabezpečení: Deklarativní syntax využívá atributy pro označení metody, třídy nebo sestavy na získání potřebných informací o zabezpečení. Takže když se sestavují, jsou uspořádány v části metadat sestavy. Deklarativní požadavky pro PrincipalPermission fungují stejným způsobem, jako deklarativní požadavky pro přístupové oprávnění ke kódu. Požadavky mohou být umístěny na úrovni třídy, stejně jako u jednotlivých metod, vlastností nebo událostí. Pokud je deklarativní požadavek umístěn na úrovni třídy i člena, tak deklarativní požadavek u člena přepíše (nebo nahradí) požadavek na úrovni třídy. Příklad 1 : Volající musí mít práva administrátora. class SecurityTest { public static void Main() { AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal); MyClass cx = new MyClass(); Console.ReadLine(); } } [PrincipalPermissionAttribute(SecurityAction.Demand, Name = null, Role = "administrators")] public class MyClass { public MyClass() { } // všechny tyto metody public void MyMethod_A() { } public void MyMethod_B() { } } Stránka 7 Chyba pokud není uživatel ve skupině administrátors. Příklad 2: Tento příklad řeší přístup do složky "c:\MyDir". Pokud kdekoliv ve třídě MyClass je volán jiný název složky, je generována chyba. class SecurityTest { public static void Main() { MyClass cx = new MyClass(); Console.ReadLine(); } } [FileIOPermissionAttribute(SecurityAction.PermitOnly, ViewAndModify = @"c:\MyDir")] public class MyClass { public MyClass() { DirectoryInfo di = new DirectoryInfo(@"c:\MyDir"); if(!di.Exists) { di.Create(); Console.WriteLine("Direktory neexistuji"); Console.ReadLine(); } //nějaký kód di.Delete(); } } Chyba pokud je volána jiná složka. Příklad 3 použití třídy UIPermission. Pokud se podíváme do dokumentace MSDN, můžete vidět tyto veřejné vlastnosti: Action - jedna z hodnot v SecurityAction enum (společná) Unrestricted - neomezený přístup ke zdroji (společné) Stránka 8 Clipboard - typ přístupu do schránky, jedna z hodnot v UIPermissionClipboard enum ( UIPermission specifické) Window - typ přístupu k oknu, jednu z hodnot v UIPermissionWindow enum ( UIPermission konkrétní). Action a Unrestricted vlastnosti jsou společné pro všechny třídy oprávnění. Clipboard a Window vlastnosti jsou specifické pro UIPermission třídy. Musíte zajistit akci, kterou užíváte a další vlastnosti, které jsou specifické pro třídu oprávnění, který používáte. Takže v tomto případě můžete psát jako následující: Možnost použití přístupu do schránky bez omezení, volaná funkce musí mít určené oprávnění. [UIPermission (SecurityAction.Demand, Clipboard = UIPermissionClipboard.AllClipboard)] public void FA(){//nějaký kód } nebo s oběma Clipboard a Window vlastnosti: Uživatelé mohou používat všechna okna windows, pro operace se schránkou, omezení jako předešlý příklad. [UIPermission (SecurityAction.Demand, Clipboard = UIPermissionClipboard.AllClipboard, Window = UIPermissionWindow.AllWindows)] public void FA(){//nějaký kód } Chcete-li deklarovat povolení s neomezeným přístupem, můžete to udělat jako následující: [UIPermission (SecurityAction.Demand, Unrestricted = true)] public void FA(){//nějaký kód } Stránka 9 Nyní se podíváme co nám nabízí výčet SecurityAction : Tento výčet určuje zabezpečení akcí, které lze provést pomocí deklarativního zabezpečení. Nabízí tyto členy: Assert -> je metoda, kterou lze volat na třídy oprávnění přístupu ke kódu a na třídu PermissionSet. Metodu Assert můžete použít k tomu, abyste vašemu kódu povolili (a volajícím ve směru server-klient) provedení akcí, ke kterým váš kód má oprávnění k provedení, ale jeho volající je mít nemusí. Kontrolní výrazy zabezpečení mění normální proces, který provádí modul runtime během kontroly zabezpečení. Zde bych použil příklad z MSDN. Budeme předpokládat, že následující příkazy jsou pravdivé u sestavení A, B, C, E a F a dvou oprávněních P1 a P1A: P1A představuje právo pro čtení .txt souborů na disku C. P1 představuje právo pro čtení všech souborů na disku C. P1A a P1 jsou obě typu FileIOPermission a P1A je podmnožinou P1. Sestavením E a F bylo uděleno oprávnění P1A. Sestavení C bylo uděleno oprávnění P1. Sestavením A a B, nebylo uděleno ani oprávnění P1 ani P1A. Metoda A je obsažena v sestavení A, metoda B je obsažena v sestavení B atd. V tomto scénáři metoda A volá B, B volá C, C volá E a E volá F. Metoda C uplatňuje oprávnění pro čtení souborů na disku C (oprávnění P1) a metoda E požaduje oprávnění ke čtení txt souborů na disku C (oprávnění P1A). Když je za běhu v metodě F objeven požadavek, je provedeno procházení zásobníku, aby se zkontrolovaly oprávnění všech volajících metody F, počínaje E. Metodě E bylo uděleno oprávnění P1A, takže procházení zásobníku pokračuje zkoumáním oprávnění metody C, kde je objeven kontrolní výraz. Protože požadované oprávnění (P1A) je podmnožinou uplatňovaného oprávnění (P1), procházení zásobníku se zastaví a kontrola zabezpečení automaticky uspěje. Nezáleží na tom, že sestavením A a B nebylo uděleno oprávnění P1A. Metoda C pomocí uplatňování P1 zajišťuje, že její volající mohou přistupovat k prostředku, který je chráněn oprávněním P1, dokonce i když volajícím nebylo uděleno oprávnění pro přístup k tomuto prostředku. Rečeno jinak, umožní kódu přístup k prostředkům, které nejsou volající funkci normálně k dispozici. Příklad 4. Následující příklad ukazuje deklarativní syntaxi pro přepsání kontroly zabezpečení pomocí metody Assert. Všimněte si, že syntaxe FileIOPermissionAttribute používá dvě hodnoty: Stránka 10 výčet SecurityAction a umístění souboru nebo adresáře, kterému je uděleno oprávnění. Volání Assert způsobí, že požadavky pro přístup k souboru C:\Temp\Log.txt proběhnou úspěšně, přestože volající nejsou zkontrolováni, zda mají oprávnění pro přístupu k souboru. //C# [FileIOPermission(SecurityAction.Assert, Append = @"C:\Temp\Log.txt")] public void MakeLog() { StreamWriter TextStream = new StreamWriter(@"C:\Temp\Log.txt"); TextStream.WriteLine("Tento protokol byl vytvořen dne: {0}", DateTime.Now); TextStream.Close(); Console.WriteLine("OK"); } Assert pro VB.NET Demand -> je metoda, která vynutí výjimku zabezpečení v době spuštění. Požaduje, aby všechny volající funkce v zásobníku volání měly určená oprávnění. LinkDemand -> nepoužívat u .NET Framework 4. Místo ní používat SecurityCriticalAttribute. Omezit používání plně důvěryhodné aplikace nebo pomocí Demand omezit částečně důvěryhodného volajícího. InheritanceDemand -> požaduje, aby bylo odvozeným třídám uděleno určené oprávnění. Platí pro dědění a přepsání (overriding). PermitOnly -> odmítne následné požadavky na prostředky, které nejsou explicitně uvedeny pomocí hodnoty PermitOnly. Prohlášení o zabezpečení akce Čas akce Podporované cíle LinkDemand (nepoužívejte v .NET Framework 4) Just-in-time kompilace Třídy, metody InheritanceDemand Čas načítání Třídy, metody Demand Čas spuštění Třídy, metody Assert Čas spuštění Třídy, metody Deny (zastaralé v .NET Framework 4) Čas spuštění Třídy, metody PermitOnly Čas spuštění Třídy, metody RequestMinimum (zastaralé v .NET Framework 4) Poskytnutí času Sestavení RequestOptional (zastaralé v .NET Framework 4) Poskytnutí času Sestavení RequestRefuse (zastaralé v .NET Framework 4) Poskytnutí času Sestavení Skrýt Kopírovat kód Příklad 5. InheritanceDemand -> Dědické nároky mohou být aplikovány na třídy nebo metody. V případě, že je aplikován na třídu, pak všechny třídy, které pocházejí z této třídy, musí mít oprávnění zadaná. Stránka 11 [SecurityPermission (SecurityAction.InheritanceDemand)] Private class MyClass () { // cokoliv } Příklad 6. V případě, že se použije metodu, pak všechny třídy, které pocházejí z této třídy, musí mít oprávnění zadaná potlačit tuto metodu. Private class MyClass () { public class MyClass () {} [SecurityPermission (SecurityAction.InheritanceDemand)] public virtual void MyMethod () { // nějaký kód } } Příklad 7. Následující příklad kódu používá požadavek dědičnosti pro vyžadování, aby jakákoliv třída, která dědí z třídy MyClass musela mít vlastní oprávnění CustomPermissionAttribute. Toto oprávnění je hypotetické vlastní oprávnění a neexistuje v rozhraní .NET Framework. Požadavek je vytvořen předáním CustomPermissionAttribute a hodnoty výčtu SecurityAction.InheritanceDemand. //C# [CustomPermissionAttribute(SecurityAction.InheritanceDemand)] public Class MyClass { public MyClass() { } public virtual string ReadData() { // Přístup k vlastnímu zdroji } } //VB.NET <CustomPermissionAttribute(SecurityAction.InheritanceDemand)> _ Public Class MyClass Public Sub New() End Sub Public Overridable Function ReadData() As String ' Přístup k vlastnímu zdroji End Function End Class Stránka 12 Příklad 8. PermitOnly -> Volání PermitOnly má v podstatě stejný účinek jako volání Deny, ale má jiný způsob specifikování podmínek, za kterých by měla selhat kontrola zabezpečení. Místo prohlašování, že specifikovaný prostředek není přístupný, jak to dělá Deny, metoda PermitOnly říká, že pouze prostředek, který specifikujete je přístupný. Proto volání PermitOnly na oprávnění X je stejné jako volání Deny na všechna oprávnění kromě oprávnění X. Pokud voláte PermitOnly, váš kód může být použit pouze pro přístup k prostředkům, které jsou chráněné oprávněními, které jste určili, když jste volali PermitOnly. Použijte PermitOnly místo Deny, když je pohodlnější popsat prostředky, které mohou být přístupné místo prostředků, které přístupné být nemohou. WebPermission myWebPermission = new WebPermission (NetworkAccess.Connect, "Http://www.somewebsite.com"); myWebPermission.PermitOnly (); // něco provádět CodeAccessPermission.PermitOnly (); // zrušit PermitOnly PermitOnly deklarativní VB.NET.vb Příklad 9. Následující fragmenty kódu ukazují deklarativní syntaxi pro přepsání kontrol zabezpečení pomocí PermitOnly. Volající nemohou použít tento kód pro přístup k žádným chráněným prostředkům kromě prostředků uživatelského rozhraní. using System.Security.Permissions; using System; public class MyClass { public MyClass() { } [UIPermissionAttribute(SecurityAction.PermitOnly, Unrestricted = true)] public void ReadRegistry() { //Access a UI resource. } } Ukázka imperativního zabezpečení: Příklad 10. Následující fragmenty kódu ukazují imperativní syntaxi pro přepsání kontroly zabezpečení pomocí metody Assert. V tomto příkladě je deklarována instance objektu FileIOPermission. Jeho konstruktoru je předán FileIOPermissionAccess.AllAccess, aby definoval typ povoleného přístupu. Následován je řetězcem, který popisuje umístění souboru. Jakmile je jednou definován objekt FileIOPermission, Musíte pouze volat jeho metodu Assert pro přepsání kontroly zabezpečení. public void MakeLog() { FileIOPermission FilePermission = new FileIOPermission(FileIOPermissionAccess.AllAccess, @"C:\Temp\Log.txt"); FilePermission.Assert(); StreamWriter TextStream = new StreamWriter(@"C:\Temp\Log.txt"); Stránka 13 TextStream.WriteLine("Tento protokol byl vytvořen dne: {0}", DateTime.Now); TextStream.Close(); Console.WriteLine("OK"); } Imperativní syntax používá metodu runtime volání k vytvoření nové instance bezpečnostních tříd. Pro imperativní požadavky můžete volat metodu Demand náležící objektu PrincipalPermission, pokud chcete zjistit, zda aktuální objekt zabezpečení představuje zadanou identitu, roli nebo obojí. Za předpokladu, že objekt PrincipalPermission je správně sestavený a nazvaný MyPrincipalPermission, imperativní požadavky mohou být volány pomocí následujícího kódu. Příklad 11. public void Fx() { FileDialogPermission fileDlgPermission = new FileDialogPermission(PermissionState.Unrestricted); fileDlgPermission.Demand (); if (myDlgForm.ShowDialog () == DialogResult.OK) MessageBox.Show (myDlgForm.FileName); } nebo: public Classs MyClass { public Moje_třída () {} public void Method_A () { // Něco udělat FileIOPermission myPerm = new FileIOPermission (PermissionState.Unrestricted); myPerm.Demand (); // Zbytek kódu nebude vykonán, pokud se to nepovedlo, // Něco udělat } // Žádné požadavky public void Method_B () { // Něco udělat } } Hlavní rozdíl mezi těmito je: deklarativní volání jsou hodnoceny v době kompilace imperativní volání jsou hodnoceny za běhu. Namespace System.Security. Obsahují třídy, které zastupují systém zabezpečení rozhraní .NET Framework, včetně oprávnění. Podřízené skupiny názvů poskytují typy, které umožňují řídit přístup k zabezpečeným objektům a auditovat je. Zajišťují ověřování uživatelů, poskytují kryptografické služby, řídí na základě zásad přístup k operacím a prostředkům a podporují správu přístupových práv k obsahu vytvořenému v dané aplikaci. Zabezpečují oprávnění základní třídy.(některé třídy - příklady) Stránka 14 CodeAccessPermission -> Definuje základní strukturu všech přístupových oprávnění ke kódu. PermissionSet -> Představuje kolekci, která může obsahovat mnoho různých druhů oprávnění. SecurityException -> Výjimka, která je vyvolána, když je zjištěna chyba zabezpečení. SecureString -> Představuje text, který by měly být důvěrný. Text je šifrovaný pro ochranu osobních údajů, je odstraněný z paměti počítače, pokud již není potřeba. Namespace System.Security.AccessControl (ACL). Množina názvů, která poskytuje programovací prvky, akce, související se zabezpečením na zabezpečené objekty auditu a řízení přístupu k těmto objektům.(některé třídy - příklady) FileSecurity -> Zabezpečuje řízení přístupu a zabezpečení pro soubor auditu. Od této třídy nelze dědit. Třída představuje sadu pravidel práv přístupu a auditování. Každé pravidlo přístupu je zastoupené objektem FileSystemAccessRule a každé pravidlo auditu je zastoupeno objektem FileSystemAuditRule. Příklad 12. Soubor, který chceme přidat musí existovat. using System; using System.IO; using System.Security.AccessControl; class FileTest { public static void Main() { try { string fileName = @"c:\Temp\Log.txt"; Console.WriteLine("Přidání položky pro řízení přístupu " + fileName); // Přidání položky pro řízení přístupu k souboru - přístup povolen AddFileSecurity(fileName, @"administrators", FileSystemRights.ReadData, AccessControlType.Allow); Console.WriteLine("Odstranění položky řízení přístupu k souboru. " + fileName); // Odstranění položky řízení přístupu k souboru. RemoveFileSecurity(fileName, @"administrators", FileSystemRights.ReadData, AccessControlType.Allow); Console.WriteLine("Hotovo."); } catch (Exception e) { Console.WriteLine(e); } finally { Console.ReadLine(); } } Stránka 15 DirectorySecurity -> Řízení přístupu a auditování zabezpečení adresáře. Od této třídy nelze dědit. MutexAccessRule -> Sadu práv přístup povolen nebo odepřen uživateli nebo skupině. Od této třídy nelze dědit. RegistrySecurity -> Zabezpečení řízení přístupu systému Windows pro klíč registru. Od této třídy nelze dědit. Namespace System.Security.Authentication.(některé výčty) Poskytuje sadu výčtů, které popisují zabezpečení spojení. Tyto výčty patří CipherAlgorithmType,ExchangeAlgorithmType, HashAlgorithmType, a SslProtocolType. ExchangeAlgorithmType -> výčet. Určuje algoritmus použitý k vytvoření sdíleného klíče klienta a serveru. CipherAlgorithmType -> výčet. Definuje možné šifrovací algoritmy pro SslStream třídu. Namespace System.Security.Cryptography. Obor názvů poskytuje kryptografických služeb, včetně zabezpečeného kódování a dekódování dat stejně jako mnoho dalších operací. Například algoritmus hash, generování náhodných čísel a ověřování zpráv. AesCryptoServiceProvider -> Provádí symetrické šifrování a dešifrování pomocí kryptografických aplikačních programovacích rozhraní (CAPI), provádění algoritmus standard AES (Advanced Encryption Standard). Příklad 13. Příklad ukazuje, jak šifrovat a dešifrovat pomocí ukázkových dat třídy AesCryptoServiceProvider. using System; using System.IO; using System.Security.Cryptography; class AesCryptographyExample { public static void Main() { try { string original = "Data, které chceme zašifrovat"; // Vytvoření nové instance AesCryptoServiceProvider class. // Vytvoření nového klíče a inicializaci vektoru (IV). using (AesCryptoServiceProvider myAes = new AesCryptoServiceProvider()) Stránka 16 { // Zde budeme šifrovat řetězec na pole bajtů byte[] encrypted = EncryptStringToBytes_Aes(original, myAes.Key, myAes.IV); // Dešifrování bajtů na řetězec string roundtrip = DecryptStringFromBytes_Aes(encrypted, myAes.Key, myAes.IV); //Zobrazení původního a dešifrovaného řetězce Console.WriteLine("Original: {0}", original); Console.WriteLine("Round Trip: {0}", roundtrip); } } catch (Exception e) { Console.WriteLine("Error: {0}", e.Message); } finally { Console.ReadLine(); } } //Šifrování internal static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key, byte[] IV) { // Kontrola, zda argumenty jsou v pořádku if (plainText == null || plainText.Length <= 0) throw new ArgumentNullException("plainText"); if (Key == null || Key.Length <= 0) throw new ArgumentNullException("Key"); if (IV == null || IV.Length <= 0) throw new ArgumentNullException("Key"); byte[] encrypted; // Vytvoření nové instance AesCryptoServiceProvider class. // Vytvoření nového klíče a inicializaci vektoru (IV). using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider()) { aesAlg.Key = Key; aesAlg.IV = IV; // Vytvořte decrytor pro provedení proudu transformace. ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV); // Vytvoření proudů k šifrování using (MemoryStream msEncrypt = new MemoryStream()) { using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) { using (StreamWriter swEncrypt = new StreamWriter(csEncrypt)) { //Zápis všech dat do proudu swEncrypt.Write(plainText); } encrypted = msEncrypt.ToArray(); } } } Stránka 17 // Návrat šifrovaných bajtů return encrypted; } //Dešifrování internal static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] Key, byte[] IV) { // Kontrola argumentů if (cipherText == null || cipherText.Length <= 0) throw new ArgumentNullException("cipherText"); if (Key == null || Key.Length <= 0) throw new ArgumentNullException("Key"); if (IV == null || IV.Length <= 0) throw new ArgumentNullException("IV"); // Declare the string used to hold // the decrypted text. string plaintext = null; // Deklarovat řetězec použitý k dešifrování textu using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider()) { aesAlg.Key = Key; aesAlg.IV = IV; // Vytvoříme decrytor k provedení proudu transformace. ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV); // Vytvoříme prudy používané k dešifrování using (MemoryStream msDecrypt = new MemoryStream(cipherText)) { using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) { using (StreamReader srDecrypt = new StreamReader(csDecrypt)) { // Načteme dešifrované bajty a umístíme je do řetězce plaintext = srDecrypt.ReadToEnd(); } } } } return plaintext; } } CryptographicException -> Výjimkou která je vyvolána, když dojde k chybě během kryptografické operace. Namespace System.Security.Permissions. Hlavní třídy, které jsou použity v tomto jmenném prostoru. EnvironmentPermission -> Kontroly přístup k systému a uživatelských proměnných. FileDialogPermission -> Ovládá možnost přístupu k souborů a složekám pomocí souborového dialogu. FileIOPermission -> Ovládá možnost přístupu k souborům a složkám. IsolatedStorageFilePermission -> Určuje povolené použití soukromého virtuálního souborového systému. Stránka 18 IsolatedStoragePermission -> Představuje přístup ke generickým ojedinělých schopností skladování. ReflectionPermission -> Kontroly přístupu k metadatům prostřednictvím System.Reflection (API). RegistryPermission -> Ovládá možnost přístupu k proměnné registru. SecurityPermission -> Popisuje sadu bezpečnostních oprávnění aplikovaných na kód. UIPermission -> Řídí oprávnění týkající se uživatelských rozhraní a schránky. Důležité třídy v jiných jmených prostorech. Namespace System.Net. WebPermission -> Určuje práva pro přístup k prostředkům v síti Internet pro protokol HTTP. SocketPermission -> Ovládací oprávnění pro příjem připojení na přepravní adresu. DnsPermission -> Ovládací prvky a jejich oprávnění pro přístup k serverům systému DNS (Domain Name) v síti. DnsPermissionAttribute -> Určuje oprávnění požadovat informace od Domain Name serverů. Příklad 14. Příklad používá DnsPermissionAttribute deklarativní zabezpečení použítí vlastní třídy. //Používá DnsPermissionAttribute omezit přístup pouze pro ty, kteří mají oprávnění. [DnsPermission(SecurityAction.Demand, Unrestricted = true)] public class MyClass { public static IPAddress GetIPAddress() { IPAddress ipAddress = Dns.Resolve("localhost").AddressList[0]; return ipAddress; } public static void Main(){ try{ //vybraný přístup Console.WriteLine(" Access granted\n The local host IP Address is :" + MyClass.GetIPAddress().ToString()); } // odepřený přístup catch(SecurityException securityException) { Console.WriteLine("Přístup zamítnut"); Console.WriteLine(securityException.ToString()); } } Namespace System.Data.SqlClient. SqlClientPermission -> Umožňuje zprostředkovateli dat .NET Framework pro SQL server pomáhat. Uživatel má úroveň zabezpečení dostatečné pro přístup ke zdroji dat. Namespace System.Diagnostics. PerformanceCounterPermission -> Umožňuje řídit přístupová oprávnění kód pro PerformanceCounter. Stránka 19 Code Access Security Policy Tool - caspol.exe Nástroj zásady zabezpečení přístupu kódu umožňuje uživatelům a správcům změnit bezpečnostní politiku na úroveň stroje politik, uživatelské úrovni politiky a podnikové úrovni politiky. Naleznete v dokumentaci MSDN pro další informace. Možnost použití pro administrátory sítí. Mnoho možností pro SecurityRuleSet.Level2 je vynecháno. Ochrana zdrojového kódu .NET. Zpětné získání zdrojového kódu u aplikací .NET Framework je snadné na příklad nástrojem JetBrains dotPeek 1.2 který je zdarma na trhu. Visual Studio 2013 dodává nástroj, který je přímo integrován a to PreEmptive Dotfuscator v menu Nástroje. Tento nástroj nepředstavuje špičku, ale je zdarma. Tyto nástroje patří ke zmatení zdrojového kódu a zamezí možnost zpětného překladu. Popis není součástí této ukázky. Ukázka použití je na příklad na webu : http://www.dirkstrauss.com/visual-studio-2012/visual-studio-2012-tips-part-5-protect-your-code-obfuscate nebo na : http://www.dotnetportal.cz/clanek/193/Ochrana-NET-aplikaci od pana Ondřeje Linharta. Pár slov k manifestu: Aplikace bude běžet ve stejném procesu jako ten, který tuto aplikaci spustil. <requestedExecutionLevel level="asInvoker" uiAccess="false" /> Aplikace se spustí s oprávněním správce. Uživatel musí být ve skupině administrators. <requestedExecutionLevel level="requireAdministrator" uiAccess="false" /> Aplikace bude běžet na nevyšší úrovni oprávnění. Pokud uživatel, který spustí aplikaci je členem skupiny administrators, tato možnost je stejná jako requireAdministrator. V případě, že nejvyšší úroveň oprávnění k dispozici je vyšší než úroveň procesu spuštění aplikace, systém vyzve k zadání pověření. <requestedExecutionLevel level="highestAvailable" uiAccess="false" /> Stránka 20
Podobné dokumenty
kapitola 18
Nepotřebná oprávnění odmítněte V zájmu principů nejmenších možných oprávnění je vhodné odmítnout oprávnění, která nepotřebujeme, i když nám je třeba běhová knihovna udělí. Pokud například daná apli...
Více