Optimalizace zabezpečení
Kontroly zabezpečení mohou způsobit potíže s výkonem pro některé aplikace. Jsou zde dva způsoby optimalizace, které můžete použít ke zlepšení výkonu. Jedna technika kombinuje požadavky zabezpečení; jiná potlačí požadavky oprávnění k volání do nespravovaného kódu. Ačkoli tyto postupy mohou zvýšit výkon aplikace, mohou také učinit aplikaci více zranitelnou vůči zneužití zabezpečení. Před použitím těchto technik optimalizace byste měli provést následující opatření:
Postupujte podle Pokyny pro zabezpečené kódování pro spravovaný kód.
Porozumějte principům zabezpečení vybrané optimalizace a chraňte aplikace podle potřeby pomocí jiných metod.
Implementujte minimální optimalizace zabezpečení povinné ke zvýšení výkonu aplikace.
Po optimalizaci kódu byste měli otestovat, zda se skutečně zlepšil výkon optimalizovaného kódu. V opačném případě byste měli odebrat optimalizace zabezpečení k pomoci chránit slabá místa zabezpečení.
![]() |
---|
Optimalizace zabezpečení vyžaduje, abyste změnili standardní zabezpečení přístupu kódu.Aby nedošlo k zavedení chyby zabezpečení do kódu, ujistěte se, že rozumíte důsledkům technik optimalizace zabezpečení před jejich použitím. |
Kombinování požadavků zabezpečení
Chcete-li optimalizovat kód, který provádí požadavky na zabezpečení, v některých situacích můžete použít techniku pro kombinování požadavků.
Například pokud:
váš kód provádí řadu operací v rámci jediné metody a
při provádění každé z těchto operací, váš kód volá do spravované knihovny tříd, která vyžaduje, aby váš kód měl stejné oprávnění pro každé volání do knihovny,
pak:
- můžete upravit kód k provedení Požadavku a Vyhodnocení tohoto oprávnění ke snížení režie vzniklé požadavky zabezpečení.
Pokud je hloubka zásobníku volání nad metodou velká, použití této techniky může mít za následek značné zvýšení výkonu.
Ke znázornění, jak toto funguje, předpokládejme, že metoda M provádí 100 operací. Každá operace zavolá do knihovny, která vyžaduje požadavek zabezpečení pro váš kód a jeho volajícím mít oprávnění X. Z důvodu požadavků zabezpečení každé operace způsobí, že modul runtime projde celý zásobník volání přezkoumáním oprávnění každého volajícího ke zjištění, zda bylo každému volajícímu skutečně uděleno oprávnění X. Pokud je zásobník volání nad metodou M n úrovní hluboký, 100n porovnání je vyžadováno.
Chcete-li optimalizovat, můžete provést následující v metodě M:
Požadujte X, což bude mít za výsledek, že modul runtime bude procházet zásobník (z hloubky n) k zajištění, že všichni volající skutečně budou mít oprávnění X.
Potom uplatněte oprávnění X, která způsobí, že následné procházení zásobníku se zastaví na metodě M a bude úspěšné, a tím sníží počet porovnání oprávnění o 99n.
V následujícím příkladu kódu metoda GetFileCreationTime přijímá řetězcové vyjádření adresáře jako parametr a zobrazí název a datum vytvoření každého souboru tohoto adresáře. Statická metoda File.GetCreationTime přečte informace ze souborů, ale vyžaduje požadavek a průchod zásobníkem pro každý soubor, který načte. Metoda vytvoří novou instanci objektu FileIOPermission, provede požadavek ke kontrole oprávnění všem volajícím v zásobníku a potom vyhodnotí oprávnění, pokud je požadavek úspěšný. Pokud byl požadavek úspěšný, bude proveden pouze jeden průchod zásobníkem a metoda čte z každého souboru v předaném adresáři čas vytvoření.
using System;
using System.IO;
using System.Security;
using System.Security.Permissions;
namespace OptimizedSecurity
{
public class FileUtil
{
public FileUtil()
{
}
public void GetFileCreationTime(string Directory)
{
//Initialize DirectoryInfo object to the passed directory.
DirectoryInfo DirFiles = new DirectoryInfo(Directory);
//Create a DateTime object to be initialized below.
DateTime TheTime;
//Get a list of files for the current directory.
FileInfo[] Files = DirFiles.GetFiles();
//Create a new instance of FileIOPermission with read
//permission to the current directory.
FileIOPermission FilePermission = new FileIOPermission(FileIOPermissionAccess.Read, Directory);
try
{
//Check the stack by making a demand.
FilePermission.Demand();
//If the demand succeeded, assert permission and
//perform the operation.
FilePermission.Assert();
for(int x = 0 ; x<= Files.Length -1 ; x++)
{
TheTime = File.GetCreationTime(Files[x].FullName);
Console.WriteLine("File: {0} Created: {1:G}", Files[x].Name,TheTime );
}
// Revert the Assert when the operation is complete.
CodeAccessPermission.RevertAssert();
}
//Catch a security exception and display an error.
catch(SecurityException)
{
Console.WriteLine("You do not have permission to read this directory.");
}
}
}
}
Option Explicit
Option Strict
Imports System
Imports System.IO
Imports System.Security
Imports System.Security.Permissions
Namespace OptimizedSecurity
Public Class FileUtil
Public Sub New()
End Sub
Public Sub GetFileCreationTime(directory As String)
'Initialize DirectoryInfo object to the passed directory.
Dim dirFiles As New DirectoryInfo(directory)
'Create a DateTime object to be initialized below.
Dim theTime As DateTime
'Get a list of files for the current directory.
Dim files As FileInfo() = dirFiles.GetFiles()
'Create a new instance of FileIOPermission with read
'permission to the current directory.
Dim filePermission As New FileIOPermission(FileIOPermissionAccess.Read, Directory)
Try
'Check the stack by making a demand.
filePermission.Demand()
'If the demand succeeded, assert permission and
'perform the operation.
filePermission.Assert()
Dim x As Integer
For x = 0 To Files.Length - 1
theTime = file.GetCreationTime(files(x).FullName)
Console.WriteLine("File: {0} Created: {1:G}", files(x).Name, theTime)
Next x
' Revert the Assert when the operation is complete.
CodeAccessPermission.RevertAssert()
'Catch a security exception and display an error.
Catch
Console.WriteLine("You do not have permission to read this directory.")
End Try
End Sub
End Class
End Namespace
Pokud je požadavek v předchozím příkladu úspěšný, každý soubor a datum a čas jeho vytvoření jsou zobrazeny pro předaný adresář. Pokud požadavek selže, je zachycena výjimka zabezpečení a na konzoli se zobrazí následující zpráva:
You do not have permission to read this directory.
Potlačení požadavků pro oprávnění nespravovaného kódu
Zvláštní optimalizace je k dispozici pro kód, který má oprávnění k volání nespravovaného kódu. Tato optimalizace umožňuje vašemu spravovanému kódu volání do nespravovaného kódu, aniž by vzniklo zvýšení procházeného zásobníku. Uplatnění oprávnění nespravovaného kódu může zkrátit procházený zásobník, ale optimalizace popsané v tomto tématu jej mohou zcela odstranit. (Viz SecurityPermission pro další informace o oprávnění k volání do nespravovaného kódu.)
Volání do nespravovaného kódu obvykle vyvolává požadavek oprávnění nespravovaného kódu, což má za následek procházení zásobníku, který určuje, zda všichni volající mají oprávnění k volání do nespravovaného kódu. Použitím vlastního atributu SuppressUnmanagedCodeSecurityAttributedo metody, která zavolá do nespravovaného kódu, potlačí požadavky. Tento atribut nahradí úplné procházení zásobníku v době běhu a zkontroluje, zda pouze v době spojení ověří oprávnění okamžitého volajícího. Ve skutečnosti tento atribut vytvoří otevřené dveře do nespravovaného kódu. Pouze kód, který má oprávnění nespravovaného kódu, může použít tento atribut; v opačném případě nebude mít žádný vliv.
![]() |
---|
Použijte atribut SuppressUnmanagedCodeSecurityAttribute pouze s mimořádnou pečlivostí.Nesprávné použití tohoto atributu může vytvořit slabá místa zabezpečení.Atribut SuppressUnmanagedCodeSecurityAttribute by neměl být nikdy použit pro umožnění méně důvěryhodnému kódu (kód, který nemá oprávnění nespravovaného kódu) volat do nespravovaného kódu. |
Tento atribut je nejlépe použit pouze pro soukromě prohlášené vstupní body do nespravovaného kódu tak, že kód jiných sestavení nemůže získat přístup a využít výhod potlačení zabezpečení. Vysoce důvěryhodný spravovaný kód, který používá tento atribut, obvykle nejprve vyžaduje některé oprávnění volajícím před vyvoláním nespravovaného kódu jménem volajícího.
Následující příklad ukazuje atribut SuppressUnmanagedCodeSecurityAttribute použitý pro soukromý vstupní bod.
<SuppressUnmanagedCodeSecurityAttribute()> Private Declare Sub
EntryPoint Lib "some.dll"(args As String)
[SuppressUnmanagedCodeSecurityAttribute()]
[DllImport("some.dll")]
private static extern void EntryPoint(string args);
Ve výjimečném případě nespravovaného kódu, který je zcela bezpečný pro všechny možné okolnosti, metoda s atributem SuppressUnmanagedCodeSecurityAttribute může být vystavena jinému spravovanému kódu přímo tím, že jej označíte jako veřejnou místo soukromou. Rozhodnete-li se vystavit metodu, která má atribut SuppressUnmanagedCodeSecurityAttribute, funkce nespravovaného kódu musí být ne pouze bezpečná, ale také nenarušitelná vůči útoku škodlivých volajících. Například kód musí pracovat odpovídajícím způsobem, i když jsou nezamýšlené argumenty vyrobeny tak, aby konkrétně způsobily selhání kódu.
Použití deklarativních přepsání a imperativních požadavků
Uplatnění a další přepisy jsou nejrychlejší, když jsou napsány deklarativně, zatímco požadavky jsou nejrychlejší při napsání imperativně. Přestože zde nemusí být výrazné zlepšení výkonu, použitím deklarativních přepisů a imperativních požadavků můžete zlepšit výkon kódu.
Viz také
Odkaz
SuppressUnmanagedCodeSecurityAttribute