načítání...
nákupní košík
Košík

je prázdný
a
b

Kniha: Bezpečný kód - David LeBlanc; Michael Howard

Bezpečný kód
-14%
sleva

Kniha: Bezpečný kód
Autor: ;

Zabezpečte své aplikace hned při jejich vývoji! Pokud píšete kód programu a bezpečnost je pro vás důležitá, tuto knihu nesmíte vynechat! První kniha, světoznámá publikace mezi ... (celý popis)
Kniha teď bohužel není dostupná.

»hlídat dostupnost


hodnoceni - 0%hodnoceni - 0%hodnoceni - 0%hodnoceni - 0%hodnoceni - 0%   celkové hodnocení
0 hodnocení + 0 recenzí

Specifikace
Nakladatelství: Computer press
Médium / forma: Tištěná kniha
Rok vydání: 2010-01-01
Počet stran: 888
Rozměr: 167 x 225 mm
Úprava: 895 stran
Vydání: Vyd. 1.
Název originálu: Writing secure code Writing secure code for Windows Vista
Spolupracovali: překlad David Krásenský, Jiří Fadrný
Vazba: vázaná s laminovaným potahem
ISBN: 9788025120507
EAN: 9788025120507
Ukázka: » zobrazit ukázku
Popis

Zabezpečte své aplikace hned při jejich vývoji! Pokud píšete kód programu a bezpečnost je pro vás důležitá, tuto knihu nesmíte vynechat! První kniha, světoznámá publikace mezi profesionálními programátory, se zaměřuje především na základní principy psaní bezpečného kódu; podrobně se věnuje základním metodám bezpečného vývoje aplikací a dotýká se i postupů při návrhu a testování. Druhá kniha ukazuje a předvádí nejlepší využití nových bezpečnostních funkcí a obranných mechanismů ve Windows Vista. Nabízí ověřené postupy při návrhu a psaní bezpečného kódu pro Vistu, i tipy z praxe. Se dvěma publikacemi v jednom svazku se mimo jiné naučíte: - Modelovat hrozby a chránit tajná data - Stanovit správné řízení přístupu - Spouštět operace vždy s nejmenšími oprávněními - Řešit problémy se vstupem ve webovém prostředí - Zabezpečovat sokety, RPC, ovládací prvky ActiveX a modely DCOM - Ochraňovat systém proti útokům s odepřením služeb - Psát bezpečný kód Microsoft .NET - Provádět bezpečnostní revize kódu - Zabudovat do aplikace soukromí a ochranu osobních údajů - Psát úplnou, jasnou a stručnou bezpečnostní dokumentaci a smysluplné chybové zprávy Autoři podávají množství příkladů kódu, na kterých ukazují konkrétní vývojářské postupy. Zdrojové kódy k příkladům z knihy citlivě lokalizované do češtiny jsou ke stažení na adrese http://knihy.cpress.cz/K1451. O autorech: Michael Howard je ve firmě Microsoft expertem v oblasti bezpečnostního vývoje. Při své práci se zabývá bezpečným návrhem, programováním a testováním v rámci iniciativy Secure Windows ve vývojovém týmu Microsoft Windows. Zároveň je jedním z architektů bezpečnostních akcí Security Push. David LeBlanc je ve společnosti Microsoft klíčovým členem iniciativy Trustworthy Computing. Pracoval také v oboru bezpečnosti sítí, při vytváření nástrojů pro audit sítí a při provádění interních penetračních testů. ([techniky a strategie tvorby bezpečných webových aplikací])

Předmětná hesla
Související tituly dle názvu:
Vývojářův kód Vývojářův kód
Cheung Ka Wai
Cena: 297 Kč
Kód 1 Kód 1
Banáš Jozef
Cena: 303 Kč
Emoční kód Emoční kód
Nelson Bradley
Cena: 318 Kč
Kód 9 Kód 9
Banáš Jozef
Cena: 191 Kč
Recenze a komentáře k titulu
Zatím žádné recenze.


Ukázka / obsah
Přepis ukázky

KAPITOLA 18

Jak psát bezpečný kód .NET

Tuto kapitolu musím zahájit menším příběhem. Když jsem si někdy v listopadu 2001při

pravoval slajdy ke dvěma přednáškám o bezpečnosti softwaru na Microsoft Professional

Developer’s Conference, řekl mi jeden známý, že brzo určitě přijdu o práci, protože

jakmile se na trhu objeví řízený kód (Managed C) a technologie .NET Framework,veš

keré bezpečnostní problémy tím provždy zmizí. Na základě tohoto tvrzení jsem upravil

svou ukázku injekce kódu SQL (rozebírali jsme ji v kapitole 12) z původního C++ na C#

– a ukázal jsem mu, jak hluboce se mýlí.

Řízený kód jistě zvládne alespoň část bezpečnostních problémů za vývojáře, zejména

pokud umíte programovat v jazyce C nebo C++, ale „vypnout mozek“ zkrátka nemůžete

nikdy, ať už se pohybujete v jakémkoli programovacím jazyce. Věřím, že si vezmete

k srdci veškeré zásady ohledně správného návrhu a kódování i z této kapitoly a že i první

aplikaci .NET budete tvořit v souladu s nimi. Říkám to z toho důvodu, že jsme dnes na

vrcholu rozšíření Microsoft .NET, a čím dříve se nám podaří posílit celkové povědomí

a čím více programátorů či vývojářů naučíme vytvářet bezpečný software hned odzačát

ku, tím lépe bude pro všechny. V této kapitole si řekneme něco o různýchbezpečnost

ních chybách, kterým se můžeme vyhnout, a také o jistých doporučených postupech,

kterých je dobré se držet při psaní kódu pod společnou běhovou knihovnou .NET CLR

(Common Language Runtime), webových služeb i XML.

K1451.indb 511K1451.indb 511 10.10.2008 13:47:1510.10.2008 13:47:15


Část III – Další techniky bezpečného kódování512

Nezapomeňte také, že řízeného kódu se týká i množství různých ponaučení ve zbytku

knížky; jako příklady mohu jmenovat:

Neukládejte tajné informace do kódu ani do souborů web.config.

Nepokoušejte se vytvářet svoje vlastní šifrování, ale využívejte raději třídy v oboru

názvů System.Security.Cryptography.

Nedůvěřujte žádnému vstupu, dokud pozitivně neověříte jeho správnost. Řízený kód, který je zajištěn ve společné běhové knihovně .NET, nám pomůže potlačit celou řadu zranitelných míst v zabezpečení (například přetečení bufferu) a také některé problémy spojené s plně důvěryhodným mobilním kódem, jako jsou ovládací prvky ActiveX. V rámci tradičního zabezpečení v Microsoft Windows se ovšem při bezpečnostních kontrolách uvažuje jen identita nositele zabezpečení (hlavního objektu, principal). Jinými slovy, pokud je daný uživatel důvěryhodný, běží příslušný kód pod jeho identitou, a je tedy také stejně důvěryhodný a má stejná oprávnění jako uživatel. Pod Windows 2000 a novějšími je k dispozici technologie založená na omezených tokenech, která uvedené problémy zčásti potlačuje; podrobnější informace k omezeným tokenům jsou uvedeny v kapitole 7. Bezpečnost v systému .NET je však ještě na vyšší úrovni a kód v něm definuje různé úrovně důvěry nejen podle toho, jaké možnosti má uživatel v systému, ale také podle systémové politiky (zásad) a podle takzvané legitimace kódu (evidence, tedy „důkazů“ o kódu). Mezi tyto legitimace patří různé vlastnosti kódu, jako je digitální podpis nebo síť jeho původu, na základě kterých tato bezpečnostní politika přidělí kódu potřebná oprávnění. To je hodně důležité, protože zejména ve světě propojeném do sítě Internet chtějíuživatelé často spouštět kód od neznámých autorů, a nemají naprosto žádnou záruku, že byl napsán bezpečně. Pokud budeme důvěřovat kódu méně než uživateli (což je jen jedna z možných kombinací důvěry k uživateli a důvěry ke kódu), mohou vysoce důvěryhodní uživatelé spouštět kód i bez nežádoucího rizika. Nejběžnějším příkladem z dnešní doby jsou skripty na webových stránkách: skript může bezpečně přijít z libovolnéhowebového serveru (za předpokladu, že je bezpečná i implementace prohlížeče), protože okruh funkcí povolených ve skriptu je přísně omezený. Bezpečnost systému .NET dálezobecňuje pojem důvěry ke kódu a nabízí mnohem silnější kompromisy mezi bezpečností a funkčností; důvěra je přitom založena jen na legitimacích, nikoli na pevném, předem určeném modelu jako u webového skriptu. Poznámka: Nejlepší a nejbezpečnější jsou podle mého názoru takové aplikace, kterévyužívají těch nejlepších bezpečnostních funkcí operačního systému a zároveň i nejlepších bezečnostních funkcí .NET, protože každý z nich řeší problémy zabezpečení z jiného pohledu. Ani jeden z těchto pohledů není univerzálním všelékem, a proto je důležité vědět, které technologie jsou při výstavbě konkrétní aplikace nejvhodnější. A o těchto nejvhodnějších technologiích rozhodneme na základě modelu hrozeb. Nenechte se ale v žádném případě ukolébat falešným pocitem bezpečí. Architektura .NET i řízený kód nabízí sice množství různých postupů pro snížení pravděpodobnosti určitých útoků, ale úplně před vším nás nikdo ochránit nedokáže. „ „ „

K1451.indb 512K1451.indb 512 10.10.2008 13:47:1510.10.2008 13:47:15


513

Důležité: Společná běhová knihovna CLR se umí bránit proti jistým typům bezpečnostních

chyb, ale to samozřejmě neznamená, že bychom mohli líně „usnout na vavřínech“. Pokud

nebudeme dodržovat základní bezpečnostní pravidla, nepomohou nám ani ty nejlepšíbez

pečnostní funkce.

Než se pustíme do slíbených nejlepších doporučených postupů, podíváme se krátce do

světa bezpečnosti kódu pro přístup v .NET, Code Access Security (CAS).

Bezpečnost kódu pro přístup: obrazem

V této části textu si stručně načrtneme základní elementy bezpečnosti kódu pro přístup

(Code Access Security, CAS) v běhové knihovně .NET CLR. Výklad je jen rámcový

a rozhodně nemá za cíl nahradit podrobné, hloubkové vysvětlení celé problematiky, jaké

najdete například v publikaci .NET Framework Security (viz odkaz v doporučenélitera

tuře), ale mělo by z něj být jasné, jak CAS funguje, a zároveň byste z něj měli pochopit

některé základní pojmy používané ve zbytku kapitoly.

Nebudu zde zacházet do přílišných podrobností a scénář podobný přístupovémuzabez

pečení CAS přiblížím raději na názorných diagramech, které hovoří o praktickém pří

kladu zapůjčení knížky z knihovny. V našem příkladu si Klára bude chtít vypůjčit knihu

z knihovny, ale protože nemá členskou průkazku, požádá o vypůjčení své dvěkamarád

ky, Vendulu a Danielu. Podívejte se na obrázek 18.1.

Obrázek 18.1 Klára si chce vypůjčit knihu z knihovny a požádá přitom své dvě kamarádky

Život ale ve skutečnosti není tak jednoduchý; konec konců, kdyby knihovníci půjčovali

knihy komukoli z ulice, za chvíli by v policích neměli nic. Knihy je proto nutné chránit

nějakou bezpečnostní či „přístupovou politikou“ – knihovna je půjčuje jen držitelům

knihovní průkazky. Jak ale vidíme z obrázku 18.2, Klára takovou průkazku nemá.

KAPITOLA 18

Jak psát bezpečný kód .NET

Kapitola 18 – Jak psát bezpečný kód .NET

„Vendulo, můžeš

mi vypůjčit jednu

knížku?“

„Danielo, můžeš

vypůjčit jednu

knížku pro Kláru?“

„Zkusím ji vypůjčit.“

Klára Vendula Daniela

K1451.indb 513K1451.indb 513 10.10.2008 13:47:1510.10.2008 13:47:15


Část III – Další techniky bezpečného kódování514

Obrázek 18.2 Platí-li „přístupová politika“ knihovny, nemůže si Klára knihu vypůjčit, protože nemá průkazku

Věřte nebo nevěřte – ale právě jste se naučili základy přístupové bezpečnosti, CAS!

Podívejme se na celý scénář ještě jednou a doplňme do něj terminologii CAS; začneme

obrázkem 18.3.

Obrázek 18.3 Zajištění platnosti „přístupové politiky“ knihovny – podle pojmů CAS

V reálném světě se asi najde hodně způsobů, jak celý systém „rozvolnit“ a jak nakonec

Kláře knihu zapůjčit, ale musí k tomu být splněny jisté podmínky, které si definuje

Vendula a Daniela. Celý scénář opět mírně přepíšeme a dostaneme se k obrázku 18.4,

kde jsou již jisté modifikátory z přístupové bezpečnosti CAS.

Knihovní

průkazka

KNIHOVNA

Knihy si může vypůjčit

jen majitel platné

průkazky

„Máte

všechny

členskou

průkazku?“

Klára Vendula Daniela

Klára Vendula Daniela

KNIHOVNA

Knihy si může vypůjčit

jen majitel platné

průkazky

Bezpečnostní

politika

Legitimace

Knihovní

průkazka

Bezpečnostní

požadavek

SestaveníŘetěz volání

Útok s

vylákáním

„Vendulo, můžeš

mi vypůjčit jednu

knížku?“

Průchod

zásobníku

„Máte

všechny

členskou

průkazku?“

K1451.indb 514K1451.indb 514 10.10.2008 13:47:1610.10.2008 13:47:16


515

Obrázek 18.4 Jak se požadavky z reálného světa promítají do zabezpečovacího systému

Jak jsem řekl už na začátku, je tento „bleskový kurs“ přístupové bezpečnosti CAS jen

stručným vysvětlením jeho činnosti, ale měli bychom z něj získat alespoň základníinfor

mace pro zbytek kapitoly.

Nástroj FxCop: povinná výbava

Než se pustíme do výkladu otázek bezpečného programování a do nejlepšíchdoporu

čených postupů, dovolím si vás upozornit na jeden užitečný nástroj, který se jmenuje

FxCop a je k dispozici na adrese http://www.gotdotnet.com.

32

Uvedený nástroj slouží

pro analýzu kódu a kontroluje, jestli dané sestavení (assembly) .NET odpovídá zása

dám .NET Framework Design Guidelines, uvedených na webové adrese http://msdn.

microsoft.com/library/en-us/cpgenref/html/cpconnetframeworkdesignguidelines.asp.

Nejlépe je proto spustit jej nad každým vytvořeným sestavením a poté nalezené chyby

v kódu opravit. Podobně jako u každého jiného nástroje i zde platí, že i když FxCop

nenalezne žádná bezpečnostní zranitelná místa, neznamená to, že je kód úplně bez

pečný; definuje ovšem alespoň jistou minimální základnu. Výsledky činnosti nástroje

nad zkušebním sestavením jsou znázorněny na obrázku 18.5.

Poznámka: Nástroj FxCop umí generovat také soubor formátu XML, do něhož zapíše veškeré

případy porušení pravidel. Chcete-li z něj dostat čitelnější zprávu, doplňte za první řádek,

<?xml version=“1.0“?> ještě druhý řádek se značkou <?xml-stylesheet href=“C:

Program FilesMicrosoft FxCopXmlviolationsreport.xsl“ type=“text/xsl“?>.

32 Poznámka českého vydavatele: Tyto stránky měly být ale společností Microsoft do měsíce července

2007 uzavřeny. Sledujte aktuální informace.

KAPITOLA 18

Jak psát bezpečný kód .NET

Kapitola 18 – Jak psát bezpečný kód .NET

Klára Vendula Daniela

„Klára nemá

průkazku, ale já se

za ni zaručím.“

„Nebudu půjčovat

knihy, které

propagují násilí!“

„Půjčím jen knihy

vytištěné po roce

1990.“

PermitOnly()Deny()Assert()

K1451.indb 515K1451.indb 515 10.10.2008 13:47:1710.10.2008 13:47:17


Část III – Další techniky bezpečného kódování516

Obrázek 18.5 Na těchto výsledcích nástroje FxCop vidíme odchylky od zásad .NET Framework Design

Guidelines

Dvěma nejběžnějšími chybami, které nástroj FxCop v kódu označuje, je chybějící silný

název sestavení a případ, kdy sestavení nespecifikuje požadavky na oprávnění. Podívejme

se nyní na obě chyby podrobněji.

Sestavení musí mít silné názvy

Názvy jsou slabou formou autentizace i legitimace („důkazů“, evidence). Pokud vám

někdo úplně neznámý předá vypálené CD, na kterém je nějaký soubor s názvem Excel.

exe, budete mu slepě důvěřovat a spustíte jej? Pokud byste zrovna nutně potřebovali

nějaký tabulkový procesor, možná byste po něm sáhli, protože byste si mysleli, že to

opravdu Microsoft Excel je. Jak to ale můžete opravdu vědět? Systém .NET řeší uvedený

problém falšování kódu pomocí silných názvů, které se skládají z prostého textového

názvu souboru, čísla verze a informace o jazykové verzi (culture) – a k nim je navíc

doplněn veřejný klíč a digitální podpis.

Silný název vytvoříme pomocí nástroje sn.exe, který vygeneruje dvojici klíčů silného

názvu; pro vytvoření dvojice klíčů zadáme příkaz sn -k keypair.snk. Výsledný sou

bor obsahuje soukromý a veřejný klíč, jenž slouží k podepsání a následnému ověření

podepsaných sestavení. (Do výkladu asymetrického šifrování se zde pouštět nebudeme;

podrobnější informace najdete ve vhodné literatuře a částečně také v kapitole 5 této

knížky.) Pokud je dvojice klíčů určena k „ostrému“ využití, nikoli pouze kexperimentál

K1451.indb 516K1451.indb 516 10.10.2008 13:47:1810.10.2008 13:47:18


517

ním účelům, musíte ji chránit stejně jako každou jinou dvojici soukromého a veřejného

klíče.

Poznamenejme ještě, že silný název je založen na samotné dvojici klíčů, nikoli nacertifikátu jako u technologie Authenticode. Jako vývojář můžete vytvořit dvojici klíčů, která

definuje váš vlastní, soukromý obor názvů; ostatní nemohou stejný obor názvů používat,

protože neznají soukromý klíč. K této dvojici klíčů si můžete následně vyžádat certifikát

(pokud chcete), ale u identity silného názvu se certifikáty nepoužívají. To znamená, že

podpis kódu nelze identifikovat jménem vydavatele, i když třeba víte, že tento stejný

vydavatel kontroluje všechny silné názvy od jisté dvojice klíčů – samozřejmě zapředpokladu, že je soukromý klíč zachován v bezpečí a soukromí.

Kromě silných názvů je vhodné doplnit sestavení (assembly) o podpis podle Authenticode

a identifikovat tak jeho vydavatele. K tomu musíte sestavení nejprve podepsat silným

názvem a poté vytvořit podpis Authenticode nad celým výsledkem. Podpis Authenticode

nemůžete generovat jako první, protože následný podpis silného názvu by byl přikontrole podpisu Authenticode považován za pozměnění dat (tampering).

Důležité: Soukromé klíče silných názvů nelze na rozdíl od certifikátů odvolat, a proto musíte

přijmout vhodná opatření pro ochranu klíčů. Jednoho velmi důvěryhodného jednotlivce

můžete například prohlásit za „mistra klíčů“, který bude soukromé klíče uchovávat na disketě,

někde v trezoru.

Poznámka: V současné době se u silných názvů používají 1024bitové klíče RSA.

Dále příkazem sn -p keypair.snk public.snk extrahujeme z dvojice klíčů příslušný

veřejný klíč. Smysl tohoto kroku pochopíte za chvíli. Proces podepisování můžeproběhnout jen během kompilace kódu a vytvoření binárního souboru, přičemž na informace

o klíči se odvoláme pomocí direktivy [assembly: AssemblyKeyFile(název-souboru)].

U výchozí aplikace ve Visual Studiu .NET se tato direktiva nachází v souboru AssemblyInfo.

cs nebo AssemblyInfo.vb a v aplikaci Visual Basic .NET vypadá následovně:

Imports System.Reflection

<Assembly: AssemblyKeyFileAttribute(„c:keyskeypair.snk“)> Uvědomte si ale také, že při takovéto operaci může být soukromý klíč zranitelný vůči prozrazení informací ze strany zlomyslného vývojáře. Toto riziko je možné potlačit pomocí odloženého podepsání, při kterém se používá jen veřejný klíč, nikoli celá dvojice soukromého a veřejného klíče. Vývojáři nemají tím pádem přístup k soukromému klíči a proces úplného podepsání se před vlastní dodávkou kódu zákazníkovi provede příkazem sn -R assemblyname.dll keypair.snk. Na vývojových počítačích musíme ale příkazem sn -Vr assemblyname.dll obejít ověření neboli verifikaci podpisu, protože takto vytvořené sestavení nemá silný název. Důležité: Mějte na paměti, že sestavení se silným názvem se může odkazovat jen na jiná sestavení, která také mají silný název.

KAPITOLA 18

Jak psát bezpečný kód .NET

Kapitola 18 – Jak psát bezpečný kód .NET

K1451.indb 517K1451.indb 517 10.10.2008 13:47:1810.10.2008 13:47:18


Část III – Další techniky bezpečného kódování518

Odložené podepisování můžeme v sestavení pod Visual Basicem .NET zajistit pomocí

následujícího řádku:

<Assembly: AssemblyDelaySignAttribute(true)> V jazyce C# vypadá podobná direktiva takto:

[assembly: AssemblyDelaySign(true)] Všimněte si tedy, že v jazyce C# je možné výraz Attribute z názvu parametru vypustit. Tip: Vývojáři, kteří na příslušném sestavení pracují denně, by měli vždy provádět odložené podepisování s veřejným klíčem. Silné názvy sestavení a ASP.NET Sestavení se silnými názvy, které implementují aplikační logiku webových aplikací, musíme pomocí nástroje .NET Configuration (Mscorcfg.msc) nebo gacutil.exe uložit do globální mezipaměti cache se sestaveními (global assembly cache, GAC), a to z důvodu, jakým ASP.NET zavádí podepsaný kód. Podívejme se nyní blíže na oprávnění a na doporučené postupy ohledně požadavků oprávnění.

Stanovení požadavků na oprávnění v sestavení

V požadavcích na oprávnění sdělujeme společné běhové knihovně .NET, jaké operace

budeme v kódu potřebovat provádět. I když zaslání požadavku na oprávnění jenepovinné a není pro kompilaci kódu nutnou podmínkou, je tento postup velice vhodný z jistých

důvodů, které poznáme až při provádění kódu. Jestliže si kód vyžádá oprávnění pomocí

metody Demand, ověří běhová knihovna CLR potřebná oprávnění i pro veškerý kód, ze

kterého bude náš kód volán. Bez těchto oprávnění požadavek selže. Při tomto ověřování

oprávnění se provádí takzvaný průchod zásobníku (stack walk). Z pohledu použitelnosti

je důležité, aby programový kód dostal veškerá oprávnění, která skutečně potřebuje ke

své práci, a z pohledu bezpečnosti je důležité, aby nedostal žádná oprávnění navíc.

Co je to průchod zásobníku?

Průchod zásobníku je důležitou součástí systému zabezpečení v běhové knihovně

.NET. Před povolením přístupu k chráněnému prostředku tak běhové prostředí ověří,

že potřebné oprávnění pro přístup k prostředku mají i všechny funkce volajícího

kódu. Hovoříme o průchodu zásobníku volání. Žádejte minimální množinu oprávnění Jestliže si vyžádáme správnou množinu oprávnění, bude mít programový kód větší šanci po svém spuštění správně pracovat. Pokud ale jasně nestanovíme minimální množinu oprávnění, kterou program potřebuje ke své činnosti, musíme do aplikace doplnit kód pro ošetření chyb a v něm elegantně obsloužit situace, kdy za běhu některé oprávnění

K1451.indb 518K1451.indb 518 10.10.2008 13:47:1910.10.2008 13:47:19


519

uděleno nebude. Vhodně vyžádaná oprávnění nám zajistí, že kód dostane skutečně ta

oprávnění, která potřebuje – nesmíme tedy žádat širší oprávnění.

Pokud kód nepřistupuje k žádným chráněným prostředkům ani neprovádí žádné bezečnostně citlivé operace, nemusíme z něj žádná oprávnění požadovat. Pokud například

aplikace potřebuje oprávnění FileIOPermission jen pro přečtení jediného souboru, stačí

do kódu zapsat následující řádek:

[assembly: FileIOPermission(SecurityAction.RequestMinimum, Read = @“c:

filesinventory.xml“)] Poznámka: Všechny parametry tohoto deklarativního oprávnění musí být známy již v době kompilace. Pomocí direktivy RequireMinimum nadefinujte minimální možnou množinu oprávnění. Pokud běhová knihovna nedokáže aplikaci přidělit tato minimální oprávnění, vyvolá výjimku PolicyException a aplikace se vůbec nespustí. 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áaplikace nebude nikdy provádět souborové operace nebo nebude přistupovat k proměnným systémového prostředí, můžeme do kódu zapsat direktivy:

[assembly: FileIOPermission(SecurityAction.RequestRefuse, Unrestricted =

true)]

[assembly: EnvironmentPermission(SecurityAction.RequestRefuse,

Unrestricted = true)] Ocitne-li se takováto aplikace v podezření z útoku vedeného přes soubory, pro který je ale potřeba mít práva přístupu k souborům, máme v rukou jasný důkaz, že náš kód být viníkem nemůže – veškerý přístup k souborům jsme v něm odmítli. Vyžádejte si volitelná oprávnění Systém zabezpečení běhové knihovny CLR dává programovému kódu možnost vyžádat si oprávnění navíc, která třeba využije, ale která pro svou činnost nepotřebuje úplně nezbytně. Rozhodnete-li se pro tento typ požadavků, nezapomeňte v kódu zachytit veškeré výjimky, k jejichž vyvolání může dojít při neúspěšném pokusu o udělení práv. Příkladem může být internetová hra, v níž si uživatel může rozehraný stav uložit dolokálního souborového systému. K tomu ale aplikace potřebuje oprávnění FileIOPermission; pokud jí je systém neudělí, bude hra funkční, pouze v ní nebude fungovat ukládánírozehraných her. Toto oprávnění si vyžádáme pomocí následujícího zápisu:

[assembly: FileIOPermission(SecurityAction.RequestOptional, Unrestricted

= true)] Pokud si v kódu nevyžádáte žádná volitelná oprávnění, budete v něm mít k dispozici všechna oprávnění přidělená díky platným zásadám, minus oprávnění, která jste vaplikaci výslovně odmítli. Zápisem této konstrukce se můžete volitelných oprávnění úplně vzdát:

KAPITOLA 18

Jak psát bezpečný kód .NET

Kapitola 18 – Jak psát bezpečný kód .NET

K1451.indb 519K1451.indb 519 10.10.2008 13:47:2010.10.2008 13:47:20


Část III – Další techniky bezpečného kódování520

[assembly: PermissionSet(SecurityAction.RequestOptional, Unrestricted =

false)] Sestavení bude mít po této direktivě za běhu přidělenu následující množinu oprávnění:

(Opr

maximální

∩ (Opr

minimální

∪ Opr

volitelná

)) – Opr

odmítnutá

To znamená, že kód bude mít přidělena ta minimální a volitelná oprávnění, která jsou

zapsána v seznamu maximálních oprávnění, minus případná odmítnutá oprávnění.

Imperativní a deklarativní oprávnění

V příkladech kódu jste si jistě všimli, že oprávnění definovaná na úrovni sestavení jsou

v jazyce C#, respektive Visual Basic .NET, zapsána do hranatých, respektive úhlových

závorek. Tyto zápisy definují takzvaná deklarativní oprávnění. Druhou možností je

zavést imperativní bezpečnost, tedy vytvořit v kódu objekty oprávnění. Příkladem

může být příkaz new FileIOPermission(FileIOPermissionAccess.Read = @“c:

filesinventory.xml“).Demand(); – ten se pokusí získat oprávnění k přečtení

souboru XML a v případě neúspěchu vyvolá výjimku.

Nezapomeňte proto v kódu odchytit všechny takovéto výjimky – jinak se provádění

aplikace zastaví.

Obě metody mají svoje výhody a nevýhody. Deklarativní oprávnění se v kódu

snadno zapisují i hledají; můžeme si je prohlížet pomocí nástroje Permissions View

(permview), který nám pomůže i při auditech a revizích kódu (pro zobrazení deklarací

zde napíšeme přepínač /decl). Ani při změnách v toku řízení programu tyto kontroly

neobejdeme a oprávnění můžeme navíc aplikovat na celé třídy.

Největší nevýhodou deklarativních oprávnění je to, že je musíme znát předem, již

v době kompilace. Další informace: Požadavky daného sestavení na oprávnění můžeme zjistit příkazem caspol -a -resolveperm myassembly.exe, který vypíše, jaká oprávnění by po zavedení daného sestavení byla přidělena, nebo pomocí nástroje permview z balíku .NET Framework sdl, který zobrazuje požadavky daného sestavení, tedy vstup do vyhodnocení zásad, kde oprávnění může, ale nemusí být přiděleno.

Příliš horlivá volání Assert

Běhová knihovna .NET CLR nabízí metodu s názvem Assert, pomocí které může kód

aplikace – a jeho prostřednictvím i další volající – „uplatnit oprávnění“ (assertpermissions), tedy provádět operace, k nimž má tento kód sám oprávnění, ale jeho volající je

již mít nemusí. Jinými slovy, volání Assert znamená: „Vím, co dělám: důvěřuj mi.“ Po

něm v kódu následuje určitá neškodná operace, ke které by normálně musel volající mít

potřebné oprávnění.

K1451.indb 520K1451.indb 520 10.10.2008 13:47:2110.10.2008 13:47:21


521

Důležité: Nepleťte si bezpečnostní metodu CodeAccessPermission.Assert ze společné

běhové knihovny .NET s funkcí assert klasického C nebo C++, případně s metodou Debug.

Assert systému .NET Framework. Zmíněné metody provádějí vyhodnocení jistého výrazu,

a pokud je jeho výsledek roven false, zobrazí diagnostickou zprávu.

Dejme tomu, že například aplikace čte určitý konfigurační nebo vyhledávací soubor, ale

volající kód nemá oprávnění k žádným souborovým I/O operacím. Pokud spolehlivě

víte, že jsou operace vašeho kódu s tímto souborem neškodné, můžete metodou Assert

„uplatnit“, že budete se souborem pracovat bezpečně.

K tomu je ovšem třeba říci, že toto uplatnění může být v některých situacích bezpečné

a v některých ne. Volání Assert se zpravidla používá v situaci, kdy vysoce důvěryhodnou

knihovnu používá nějaký méně důvěryhodný kód a kdy je nutné zastavit průchodzásob

níku. Představte si například, že vytvoříte implementaci třídy pro přístup k souborům

přes rozhraní USB (Universal Serial Bus); tato třída bude mít název UsbFileStream a bude

odvozena od třídy FileStream. Nový kód bude k souborům přistupovat prostřednictvím

volání API rozhraní USB Win32, ale rozhodně nebude od všech svých volajícíchvyža

dovat oprávnění k volání neřízeného kódu; bude mu stačit oprávnění FileIOPermission.

Kód třídy UsbFileStream provede proto ve volání Assert operaci UnmanagedCode (aby

mohl pracovat s Win32 API) a vyžádá si oprávnění FileIOPermission, se kterýmpotvr

dí, že volající má povoleno provést danou I/O operaci nad souborem.

Jestliže ale nyní nějaký kód převezme název souboru z nedůvěryhodného zdroje,napří

klad od uživatele, a poté jej otevře pro operaci zkrácení, jistě si nepočíná bezpečně. Co

když třeba uživatel předá do programu požadavek, jako například ../../boot.ini? Vymaže

program skutečně soubor boot.ini? Je možné, že se to opravdu stane – zejména pokud

je přístupový seznam (ACL) na tomto souboru slabý, pokud aplikace běží pod účtem

administrátora nebo pokud je soubor umístěn na diskovém oddíle FAT.

Při provádění bezpečnostní revize kódu se podívejte na veškerá bezpečnostní„uplatně

ní“ Assert a raději dvakrát zkontrolujte, jestli jsou následné operace opravdu neškodné,

zejména pokud v kódu objevíte samostatné Assert bez odpovídajícího Demand nebo

pokud u slabého oprávnění najdete Assert a Demand zároveň. Takto můžeme například

přes Assert zavolat neřízený kód a poté si přes Demand vyžádat oprávnění pro přístup

k proměnné systémového prostředí.

Poznámka: Jestliže v kódu potřebujeme uplatnit nějaké oprávnění ve volání Assert,musí

me toto oprávnění nejprve mít přidělené.

Důležité: Dávejte si velký pozor zejména na situace, kdy v kódu pomocí zápisu

SecurityPermissionFlag.UnmanagedCode uplatňujete oprávnění k volání neřízeného kódu;

pokud se vám v kódu podaří udělat chybu, můžete nakonec způsobit neúmyslné vyvolání

neřízeného kódu.

KAPITOLA 18

Jak psát bezpečný kód .NET

Kapitola 18 – Jak psát bezpečný kód .NET

K1451.indb 521K1451.indb 521 10.10.2008 13:47:2110.10.2008 13:47:21


Část III – Další techniky bezpečného kódování522

Další informace k voláním Demand a Assert

Při vytváření aplikací s metodami Demand a Assert je třeba dodržovat několik jedno

duchých pravidel. Z kódu je tak především nutné metodou Assert uplatnit jedno nebo

více oprávnění v případě, kdy provádíme nějakou privilegovanou, i když bezpečnou

operaci a kdy zároveň nechceme toto oprávnění požadovat po volajícím. Poznamenejme,

že kód musí mít oprávnění, které v metodě Assert uplatňujeme, a také oprávnění

SecurityPermissionFlag.Assert, tedy oprávnění k volání metody Assert.

Pokud například uplatníme oprávnění FileIOPermission, musí mít náš kód toto

oprávnění uděleno, ale volající kód je již nepotřebuje. Jestliže uplatníme oprávnění

FileIOPermission za situace, kdy je v kódu uděleno nemáme, provede se průchodzásob

níku a poté dojde k vyvolání výjimky.

Jak jsem se již zmínil, pokud vyžadujeme vlastnictví příslušného oprávnění od volají

cích, musíme si je vyžádat („poptávat“) z kódu v požadavku, který odešleme metodou

Demand. Dejme tomu, že například aplikace odesílá ostatním jistá oznámení pomocí

elektronické pošty a že za tímto účelem definuje jisté vlastní oprávnění s názvem

EmailAlertPermission. Jakmile nějaký volající kód vyvolá naši aplikaci, budeme pomocí

metody Demand vyžadovat toto oprávnění u všech volajících; pokud volající nemáopráv

nění EmailAlertPermission přiděleno, požadavek selže.

Důležité: Při požadavku (Demand, „poptávce“) se udělení příslušného oprávnění nekontroluje

u kódu, který provedl metodu Demand, ale jen u jeho volajících. Máme-li například ve funkci

Main přidělena omezená oprávnění, proběhne u ní kontrola jakéhokoli požadavku úspěšně

– protože tato funkce již nemá žádného volajícího. Proto potřebujete-li ověřit oprávnění

vlastního kódu, musíte v něm buďto vyvolat určitou funkci a metodu Demand vyvolat tepr

ve zde – tím se odhalí oprávnění volajícího – anebo pomocí metody SecurityManager.

IsGranted přímo zjistit oprávnění přidělená danému sestavení (a to pouze tomuto sestavení,

protože volající již stejná oprávnění mít nemusí). To ale rozhodně neznamená, že do funkce

Main můžete napsat jakýkoli škodlivý kód a že bude fungovat! Pokud kód vyvolává třídy,

které se pokoušejí o provedení potenciálně nebezpečných operací, proběhne následněprů

chod zásobníku a kontrola oprávnění.

Důležité: Jestliže z kódu aplikace vyvoláváte jiný kód, který požaduje určitá oprávnění,

neprovádějte stejný požadavek z vlastní aplikace. Důvod souvisí s rychlostí zpracování

– nemá smysl provádět takto dvojí průchod zásobníku. Jinými slovy, pokud vyvoláte někde

z kódu metodu Environment.GetEnvironmentVariable, nemusíte již zvlášť požadovat

oprávnění EnvironmentPermission, protože systém .NET Framework to udělá za nás.

Napsat kód, který uplatňuje (Assert) a požaduje (Demand) oprávnění, není nijak těžké.

Budeme-li například pokračovat ve výše uvedeném scénáři s e-mailovýmiupozornění

mi, může kód, který již přímo komunikuje s podsystémem elektronické pošty,požado

vat u všech volajících oprávnění EmailAlertPermission (to je námi definované, vlastní

oprávnění). Poté tento kód zapíše e-mailovou zprávu do portu SMTP a přitom může

uplatnit oprávnění SocketPermission. V tomto scénáři mohou volající programyvyuží

vat náš kód k zasílání elektronické pošty, ale již nebudou mít možnost odesílat data do

K1451.indb 522K1451.indb 522 10.10.2008 13:47:2210.10.2008 13:47:22


523

libovolného portu – přestože to umožňuje oprávnění SocketPermission (to je uděleno

jen našemu kódu, nikoli volajícímu).

Kde je oprávnění UnmanagedCode?

Možnost volání neřízeného kódu je vysoce privilegovaným oprávněním. Jakmile totiž

„unikneme“ z prostoru řízeného kódu, můžeme na počítači dělat v podstatě cokoliv,

samozřejmě podle možností daného uživatelského účtu. Kde je tedy oprávnění

UnmanagedCode? Je „zastrčené“ dovnitř jiného oprávnění.

U některých funkcí provádíme jednoduché „binární“ rozhodnutí ano/ne, zatímco

jiné jsou složitější. Také možnost volání neřízeného kódu je binárního typu – tento

kód zkrátka volat můžeme, nebo nemůžeme. Možnost přístupu k souborům, kterou

ovládá třída oprávnění FileIOPermission, je oproti tomu složitější: kód může mít

přiděleno právo čtení z jednoho souboru a zápisu do jiného souboru – nejedná se

tedy o jednoduché „binární“ rozhodování. Oprávnění k volání neřízeného kódu je

definováno různými příznaky ve třídě SecurityPermission, jak vidíme v následujícím řádku:

[SecurityPermission(SecurityAction.Assert, UnmanagedCode=true)] A nakonec, metodu Permission.Assert nemůžeme volat dvakrát po sobě – jinak vyvolá výjimku. Proto potřebujete-li v aplikaci uplatnit více než jedno oprávnění, musíte nejrve vytvořit množinu oprávnění, vložit do ní jednotlivá oprávnění a nakonec metodou Assert uplatnit celou množinu, například:

try {

PermissionSet ps =

new PermissionSet(PermissionState.None);

ps.AddPermission(new FileDialogPermission

(FileDialogPermissionAccess.Open));

ps.AddPermission(new FileIOPermission

(FileIOPermissionAccess.Read.@“c:files“));

ps.Assert();

} catch (SecurityException e) {

// auuu!

}

Asertivní okno při uplatnění musí být malé

Po dokončení operace, ke které potřebujeme oprávnění speciálně uplatněné metodou Assert, je třeba toto uplatnění odvolat pomocí metody CodeAccessPermission.

RevertAssert. To je opět příklad s nejmenším možným oprávněním: uplatněné apřidělené oprávnění použijeme jen po dobu, kdy je to nezbytně nutné, a poté je „poslušně“

vrátíme.

Následující ukázka programového kódu v C# používá vhodnou kombinaci uplatnění

(Assert), požadavků či „poptávek“ (Demand) a vracení (Revert) oprávnění pro rozesílání

e-mailových upozornění. Volající musí mít oprávnění k odesílání elektronické pošty,

a pokud je skutečně má, může odesílat e-mail přes soket SMTP, přestože oprávnění

k otevření obecného soketu již nemá:

KAPITOLA 18

Jak psát bezpečný kód .NET

Kapitola 18 – Jak psát bezpečný kód .NET

K1451.indb 523K1451.indb 523 10.10.2008 13:47:2310.10.2008 13:47:23


Část III – Další techniky bezpečného kódování524

using System;

using System.Net;

using System.Security;

using System.Security.Permissions;

// Toto je pouze fragment kódu; chybí zde třídy a obory názvů.

static void SendAlert(string alert) {

// Požadavek po oprávnění volajícího k odesílání e-mailu.

new EmailAlertPermission(

EmailAlertPermission.Send).Demand();

// Zde v kódu otevřeme konkrétní port na konkrétním serveru SMTP.

NetworkAccess na = NetworkAccess.Connect;

TransportType type = TransportType.Tcp;

string host = „mail.northwindtraders.com“;

int port = 25;

new SocketPermission(na, type, host, port).Assert();

try {

SendAlertTo(host, port, alert);

} finally {

// Vždy oprávnění vrátíme, i při selhání

CodeAccessPermission.RevertAssert();

}

} Pokud se volání metod Assert, Deny a PermitOnly nacházejí na stejném objektu, provádí se nejprve akce Deny, poté Assert a nakonec PermitOnly. Představte si metodu A(), která zavolá metodu B(), z ní se potom vyvolá metoda C(), přičemž metoda A() odepře oprávnění ReflectionPermission. Metoda C() může ale ještě oprávnění ReflectionPermission uplatnit (voláním Assert), samozřejmě za podmínky, že sestavení, které ji obsahuje, má toto oprávnění přiděleno. Proč to? Protože jakmile běhová knihovna narazí na uplatnění (metodu Assert), zastaví průchodzásobníku a k odepřenému oprávnění v metodě A() se již nedostane. Následující příklad kódu ukazuje celý tento postup na jediném sestavení:

private string filename = @“c:filesfred.txt“;

private void A() {

new FileIOPermission(

FileIOPermissionAccess.AllAccess,filename).Deny();

B();

}

private void B() {

C();

}

private void C() {

try {

new FileIOPermission(

FileIOPermissionAccess.AllAccess,filename).Assert();

try {

StreamWriter sw = new StreamWriter(filename);

sw.Write(„Ahoj!“);

sw.Close();

K1451.indb 524K1451.indb 524 10.10.2008 13:47:2310.10.2008 13:47:23


525

} catch (IOException e) {

Console.Write(e.ToString());

}

} finally {

CodeAccessPermission.RevertAssert();

}

} Jestliže volání Assert z metody C() odstraníte, vyvolá kód při instanciaci třídy StreamWriter výjimku SecurityException, protože kódu je již oprávnění odepřeno.

Požadavky a požadavky na odkaz

Už jsme si ukázali příklad kódu, který ke své správné činnosti „poptává“ neboli požaduje (demand) jistá oprávnění. Většina tříd v systému .NET Framework má již určité

požadavky přidružené, takže při volání třídy, která přistupuje k nějakému chráněnému

prostředku, již není nutné zasílat další požadavek. Třída System.IO.File například při

otevření jakéhokoli souboru z kódu automaticky požaduje oprávnění FileIOPermission.

Pokud někde v kódu používáte třídu File, ale ještě vyvoláte zvláštní požadavek pooprávnění FileIOPermission, znamená to jen redundantní a zbytečný průchod zásobníku.

Pomocí požadavku musíte ochránit zejména svoje vlastní prostředky, ke kterým jsou

potřeba vlastní oprávnění.

U požadavku na odkaz (link demand) se provádí bezpečnostní kontrola až běhemběhové kompilace volající metody (to je kompilace v režimu „právě včas“, just-in-time, JIT)

a kontroluje se pouze bezprostředně vyšší volající kód, ze kterého byl náš kód vyvolán.

Pokud tento volající nemá dostatečná oprávnění k odkazu na náš kód – tedy pokud

například z našeho kódu od volajícího kódu požadujeme za běhu oprávnění Isolated

StorageFilePermission – není odkaz povolen a běhová knihovna vyvolá při zavedení

a spuštění kódu výjimku.

Při požadavcích na odkaz se neprovádí úplný průchod zásobníku, a proto je náš kód opět

zranitelný vůči útoku s vylákáním (luring attack) – to znamená, že méně důvěryhodný

kód zavolá náš vysoce důvěryhodný kód a zneužije jej k provedení neoprávněnýchoperací. Požadavek na odkaz vyjadřuje pouze ta oprávnění, která musí mít volající kód při

odkazu na náš kód; nevyjadřuje již, jaká oprávnění musí mít volající kód při vlastním

spuštění kódu. Tato oprávnění je možné zjistit pouze průchodem zásobníku.

Příklad bezpečnostní chyby s voláním LinkDemand

Konečně se dostáváme ke slíbenému problému. Podívejte se na následující ukázku

kódu:

[PasswordPermission(SecurityAction.LinkDemand, Unrestricted=true)] [Regis

tryPermissionAttribute(SecurityAction.PermitOnly,

Read=@“HKEY_LOCAL_MACHINESOFTWAREAccountingApplication“)]

public string returnPassword() {

return (string)Registry

.LocalMachine

.OpenSubKey(@“SOFTWAREAccountingApplication“)

.GetValue(„Password“);

KAPITOLA 18

Jak psát bezpečný kód .NET

Kapitola 18 – Jak psát bezpečný kód .NET

K1451.indb 525K1451.indb 525 10.10.2008 13:47:2310.10.2008 13:47:23


Část III – Další techniky bezpečného kódování526

}

...

public string returnPasswordWrapper() {

return returnPassword();

} Ano, vím a jistě víte i vy – tento kód je nebezpečný proto, že přenáší tajné informace dovnitř samotného kódu, ale budu hovořit ještě o něčem jiném. Při volání funkcereturnPassword musí mít volající kód vlastní oprávnění s názvem PasswordPermission. Pokud by kód provedl volání returnPassword bez uvedeného oprávnění, vyvolala by běhová knihovna bezpečnostní výjimku a kód by se k heslu nedostal. Jestliže ale kód vyvolá obálkovou funkci returnPasswordWrapper, odešle se požadavek na odkaz pouze nad vyvolanou funkcí returnPassword a nikoli nad kódem, který vyvolal funkcireturnPasswordWrapper, protože požadavek na odkaz jde vždy pouze o jednu úroveň do hloubky. Kód, který zavolal funkci returnPasswordWrapper, se tím pádem k heslu dostane. Protože požadavky na odkaz se provádějí až za běhu, v režimu JIT a protože se při nich ověřuje jen tolik, jestli má přímý volající potřebné oprávnění, jsou rychlejší než úplné požadavky, ale zároveň poskytují potenciálně slabší bezpečnostní mechanismus. Jaké je z tohoto „příběhu“ ponaučení? Nikdy nepoužívejte požadavky na odkaz, pokud jste kód nepodrobili opravdu důkladné revizi. Provedení jednoho požadavku i s úplným průchodem zásobníku trvá sotva několik mikrosekund, takže pokud nahradíteplnohodnotné požadavky za požadavky na odkaz, rozdíl v rychlosti zpracování ani nepostřehnete. Máte-li ale požadavky na odkaz v kódu, raději si dvakrát zkontrolujte, jestli v nich nejsou nějaké bezpečnostní chyby – a to zejména tehdy, pokud nemůžete splnění příslušných kontrol v době odkazování zaručit úplně u každého volajícího. Podobně pokud vyvoláte z aplikace nějaký cizí kód, který provádí požadavky na odkaz, zeptejte se: neprovádíte ve svém kódu nějaké operace, které by mohly tyto požadavky narušit? A nakonec, jestliže je požadavek na odkaz definován nad virtuálním odvozeným elementem, zkontrolujte, jestli stejný požadavek existuje také na příslušném bázovém elementu. Důležité: Reflexní vrstva běhové knihovny provádí při operaci požadavku Demand úplný průchod zásobníku, přičemž u všech případů pozdní vazby (late-bound) pracuje podstejnými oprávněními; účelem je zabránit zneužití požadavku LinkDemand i zneužití reflexe (to je proces získávání informací o sestaveních a typech a dále vytvoření, vyvolání a přístupu kinstancím typu za běhu). Tím je potlačeno riziko možného přístupu k chráněnému členuprostřednictvím reflexe, ke kterému by jinak mohlo dojít i v případě, že by při normální včasné vazbě (early-bound) nebyl přístup dovolen. Při úplném průchodu zásobníku se ovšem mění sémantika požadavku na odkaz, vyvolaného původně prostřednictvím reflexe, a navíc je tato operace pomalejší; proto je vhodnější použít raději úplný požadavek. Tím je celý proces nejen rychlejší, ale i srozumitelnější.

K1451.indb 526K1451.indb 526 10.10.2008 13:47:2310.10.2008 13:47:23


527

S atributem SuppressUnmanagedCodeSecurityAttribute

opatrně

Jestliže v kódu pracujete s atributem SuppressUnmanagedCodeSecurityAttribute,dávejte opravdu hodně velký pozor. Normálně může volání do neřízeného kódu proběhnout

úspěšně jen tehdy, pokud mají všechny volající moduly oprávnění volat neřízený kód.

Pokud na metodu, která provádí volání do neřízeného kódu, aplikujeme vlastní atribut

SuppressUnmanagedCodeSecurityAttribute, „poptávka“ neboli požadavek se tímpotlačí. Namísto úplného požadavku provede kód pouze požadavek na odkaz s možností

volání neřízeného kódu. Jestliže z kódu budete volat větší množství nativních funkcí

Win32, může se tím kód výrazně urychlit, ale řešení je zároveň i nebezpečné. Následující

fragment kódu aplikuje atribut SuppressUnmanagedCodeSecurityAttribute na metodu

(funkci) MyWin32Function:

using System.Security;

using System.Runtime.InteropServices;

...

public class MyClass {

...

[SuppressUnmanagedCodeSecurityAttribute()]

[DllImport(„MyDLL.DLL“)]

private static extern int MyWin32Function(int i);

public int DoWork() {

return MyWin32FunctionC0x42);

}

} Ve všech metodách, které uvedený atribut používají, raději dvakrát zkontrolujtebezpečnost kódu. Důležité: Volání LinkDemand a atribut SuppressUnmanagedCodeSecurityAttribute mají něco společného – u obou se musíme rozhodnout mezi rychlostí kódu a jeho bezpečností. Nezapínejte proto uvedené prvky nahodile a vždy si pečlivě prověřte, jestli potenciální urychlení kódu stojí za riziko vyšší bezpečnostní zranitelnosti. Uvedené funkce nezapínejte, dokud měřením nepotvrdíte urychlení kódu (pokud zde vůbec nějaké urychlení je). Pokud se rozhodnete zapnout funkci SuppressUnmanagedCodeSecurity, dodržujte tyto doporučené postupy: nativní metody deklarujte jako private nebo internal a všechny argumenty ve volání metody je nutné validovat.

Vzdálené požadavky

Pokud je určitý objekt možné volat vzdáleně (tedy pokud je objekt odvozen od třídy

MarshalByRefObject) a pokud k němu přistupujeme na dálku přes hranice procesů

nebo počítačů, bezpečnostní kontroly přístupového kódu jako Demand, LinkDemand

a InheritanceDemand se neprovádějí. To například znamená, že bezpečnostní kontroly

neprocházejí v prostředí webových služeb přes protokol SOAP. Bezpečnostní kontroly

přístupového kódu procházejí ovšem přes aplikační domény. Stojí také za zmínku, že

vzdálené volání je podporováno jen v plně důvěryhodných prostředích. Jinými slovy,

KAPITOLA 18

Jak psát bezpečný kód .NET

Kapitola 18 – Jak psát bezpečný kód .NET

K1451.indb 527K1451.indb 527 10.10.2008 13:47:2410.10.2008 13:47:24


Část III – Další techniky bezpečného kódování528

pokud je nějaký kód považován na klientu za plně důvěryhodný, nemusí být plnědůvěryhodným i v kontextu serveru.

Omezte přístup k vašemu kódu

Volání některých metod našeho vlastního kódu je někdy nevhodné dovolit úplnějakémukoli, i nedůvěryhodnému kódu. Metoda může například poskytovat jisté omezené

informace nebo třeba z různých důvodů provádí jen minimální kontroly chyb. Řízený

kód nabízí několik způsobů pro omezení přístupu k metodám; nejjednodušší je omezit

obor třídy (scope), sestavení nebo odvozené třídy. Poznamenejme přitom, že odvozená

třída může být méně důvěryhodná než třída, ze které je odvozena; konec konců nikdy

nevíme, kdo se rozhodne z naší třídy odvodit nějaký jiný kód. Důvěryhodnost kódu

nelze mlčky vyvozovat ani z klíčového slova protected, které z bezpečnostního hlediska

neznamená vůbec nic. Člen třídy typu protected je dostupný zevnitř třídy, v níž byl sám

deklarován, a také z jakékoli třídy, která je z této původní třídy odvozená – podobně jako

je klíčové slovo protected definováno ve třídách C++.

Třídy je dále vhodné zapečetit. Zapečetěné třídy (sealed classes) – ve Visual Basicu se

označují jako neděděné, NotInheritable – jsou zkrátka takové třídy, které nelze podědit

(odvodit). Jinými slovy, zapečetěnou třídu nelze použít jako bázovou třídu pro definici

jiné třídy. Pokud takovouto třídu nadefinujeme v kódu, výrazně tím omezíme kód, který

bude naše třídy dědit. Nezapomeňte přitom, že žádnému kódu, vytvořenému děděním

z naší třídy, nemůžeme důvěřovat – jedná se tedy o rozumnou „hygienu“ objektověorientovaného programování.

Dále můžeme omezit metody přístupu pro volající jen na zvlášť vybrané metody.

Podobně v rámci deklarativní bezpečnosti můžeme řídit dědění tříd. Pomocí volání

InheritanceDemand nařídíme pro odvozené třídy zadanou identitu nebo oprávnění,příadně budeme požadovat určitou identitu nebo oprávnění v každé třídě, která přepisuje

(override) nějaké metody. Takto například nadefinujeme třídu, kterou je možné vyvolat

pouze z takového kódu, jenž má oprávnění EnvironmentPermission:

[EnvironmentPermission

(SecurityAction.InheritanceDemand, Unrestricted=true)]

public class Karel {

...

}

class Pepa : Karel {

...

} V tomto příkladu musí třída Pepa, která je vytvořena zděděním třídy Karel, mítoprávnění EnvironmentPermission. Požadavek po dědění jde ještě o jeden krok dále – můžeme pomocí ní omezit, jaký kód může přepisovat virtuální metody. Takto můžeme například požadovat vlastní oprávnění PrivateKeyPermission u každé metody, která se pokusí přepsat virtuální metodu SetKey:

[PrivateKeyPermission

(SecurityAction.InheritanceDemand, Unrestricted=true)]

public virtual void SetKey(byte [] key) {

K1451.indb 528K1451.indb 528 10.10.2008 13:47:2410.10.2008 13:47:24


529

m_key = key;

DestroyKey(key);

} Kromě toho je možné omezit, z jakých sestavení je možné kód vyvolat; povolenásestavení definujeme pomocí jejich silného názvu:

[StrongNameIdentityPermission(SecurityAction.LinkDemand, PublicKey=“00240

fd981762bd0000...172252f490edf20012b6“)] A kód můžeme také svázat zpět se serverem, kde tento kód vznikl. Uvedená funkce je podobná mechanismu šablony SiteLock, který byl popsán v kapitole 16. Celý postupukazuje následující kód, ale pamatujte si – ani tento kód není náhradou dobréhozabezpečení přístupového kódu. Nepište žádný nebezpečný kód ve falešné naději, že přece bude instanciován jen z jednoho konkrétního webového serveru a že se k němu tedy žádný zlomyslný uživatel nedostane. Pokud nevíte, proč byste to neměli dělat, vzpomeňte si na problémy s křížovými skripty mezi servery!

private void function(string[] args) {

try {

new SiteIdentityPermission(

@“*.explorationair.com“).Demand();

} catch (SecurityException e){

// kód nebyl vyvolán ze serveru Exploration Air

}

}

V kódu XML ani konfiguračních souborech nesmí být

citlivá data

Vím, že jsem to už říkal na začátku této kapitoly, ale stojí za to si připomenout ještějednou. Do konfiguračních souborů, jako je například web.config, můžete ukládat jakékoli

údaje, jen pokud nejsou citlivé. Hesla, klíče a řetězce pro připojení k databázi je ale třeba

uložit někde, kde budou před zraky útočníků skryté. Umístit citlivá data do registru je

mnohem bezpečnější, než je takto nechat „napospas ďáblu“. Je jasné, že se tímtovzdáváme možnosti nasazení aplikace jediným příkazem xcopy, ale život už je takový.

ASP.NET verze 1.1 podporuje volitelné rozhraní Data Protection API pro šifrovánítajných dat, uložených v chráněném klíči systémového registru. (Podrobnější informace

o rozhraní DPAPI jsou uvedeny v kapitole 9.) Uvedený mechanismus můžeme využít

především v konfiguračních sekcích <processModel>, <identity> a <sessionState>. Při

zapnutém šifrování obsahuje konfigurační soubor odkaz na klíč registru a na hodnotu,

v níž jsou tajné informace uloženy. Chráněné tajné informace vytvoříme v ASP.NET

pomocí malé utility příkazového řádku s názvem aspnet_setreg. Podívejme se na malý

příklad konfiguračního souboru, který načítá uživatelské jméno a heslo, pod nímž se

spouští pracovní proces ASP.NET:

<system.web>

<processModel

enable=“true“

userName=“registry:HKLMSoftwareSomeKey,userName“

password=“registry:HKLMSoftwareSomeKey,passWord“

KAPITOLA 18

Jak psát bezpečný kód .NET

Kapitola 18 – Jak psát bezpečný kód .NET

K1451.indb 529K1451.indb 529 10.10.2008 13:47:2510.10.2008 13:47:25


Část III – Další techniky bezpečného kódování530

...

/>

</system.web> Tajné informace zde chrání funkce CryptProtectData pomocí šifrovacího klíčedefinovaného na úrovni počítače. Ta sice nedokáže potlačit veškeré hrozby spojené s ukládáním tajných informací – pokud má někdo k počítači fyzický přístup, dostane se i k uloženým tajným datům – ale oproti ukládání dat do běžného konfiguračního souboru vnešifrované podobě znamená výrazně vyšší bezpečnost. Uvedená technika neslouží ovšem pro ukládání libovolných aplikačních dat – je určena pouze pro uživatelská jména a hesla, která se používají v identitě procesu ASP.NET, a pro data o spojení stavové služby.

Kontrolujte sestavení, která umožňují částečnou důvěru

Dobře si pamatuji na den, kdy bylo přijato rozhodnutí doplnit do systému .NET atribut

AllowPartiallyTrustedCallersAttribute. Zdůvodnění bylo naprosto logické: většina

útoků pochází přece z Internetu, jehož kódu je možné částečně důvěřovat – to znamená,

že kódu povolíme provádění jistých operací a jiné nikoli. Firma může tak například

vynucovat bezpečnostní politiku, podle níž bude volání kódu z Internetu do otevřeného

soketového spojení zpět na zdrojovém serveru povoleno, ale nad tímto spojením nebude

možné tisknout dokumenty ani číst a zapisovat soubory. Přijali jsme tudíž rozhodnutí

nedovolit částečně důvěryhodnému kódu přístup k určitým sestavením, která sedodávají s knihovnou CLR a systémem .NET Framework – a to znamená ve výchozím nastavení

také veškerý kód vytvořený libovolnou ze třetích stran, tedy i vámi samotnými. Tím se

v cílovém prostředí výrazně zúží potenciální plocha útoku. Tento den si opravdu dobře

pamatuji, protože zmíněný nový atribut zakazuje nahodilé volání inkriminovaného kódu

z potenciálně nepřátelského internetového kódu. Nastavení této volby provede nazákladě svého rozhodnutí vývojář aplikace.

Jestliže vytváříte kód, který může být vyvolán z částečně důvěryhodného kódu, a jestliže

jste jej podrobili důkladnými revizím i bezpečnostnímu testování, můžete zmíněný typ

volání povolit pomocí vlastního atributu AllowPartiallyTrustedCallersAttribute,

definovaného na úrovni sestavení:

[assembly:AllowPartiallyTrustedCallers] Sestavení, která povolují spouštění od částečně důvěryhodných volajících, by neměla nikdy dávat k dispozici objekty pocházející z jiných sestavení, která částečnědůvěryhodné volající nepřipouštějí. Důležité: Nezapomeňte, že sestavení bez silného názvu se z částečně důvěryhodného kódu dají vyvolávat vždy. A nakonec, pokud váš kód není plně důvěryhodný, nemůže často vyvolávat jiný kód, který vyžaduje plně důvěryhodné volající – jako jsou například sestavení se silnými názvy, u nichž atribut AllowPartiallyTrustedCallersAttribute definován není.

K1451.indb 530K1451.indb 530 10.10.2008 13:47:2510.10.2008 13:47:25


531

Dále si dávejte pozor na následující scénář, ve kterém se sestavení rozhodne odmítnout

určitá oprávnění:

Sestavení A se silným názvem nemá definován atribut AllowPartiallyTrustedCall

ersAttribute.

Sestavení B se silným názvem pomocí požadavku oprávnění odmítne oprávnění, což

znamená, že se stane jen částečně důvěryhodným – nemá už totiž plnou důvěru.

Nyní již sestavení B nemůže vyvolávat kód v sestavení A, protože A částečnědůvěryhodné volající nepodporuje. Důležité: Atribut AllowPartiallyTrustedCallersAttribute je vhodné a



       
Knihkupectví Knihy.ABZ.cz - online prodej | ABZ Knihy, a.s.
ABZ knihy, a.s.
 
 
 

Knihy.ABZ.cz - knihkupectví online -  © 2004-2018 - ABZ ABZ knihy, a.s. TOPlist