Megosztás a következőn keresztül:


Ajánlott megbízhatósági eljárások

A következő megbízhatósági szabályok az SQL Serverre vonatkoznak; azonban minden gazdagépalapú kiszolgálóalkalmazásra is érvényesek. Rendkívül fontos, hogy az olyan kiszolgálók, mint az SQL Server, ne szivárogtatják ki az erőforrásokat, és ne legyenek lehozva. Ezt azonban nem lehet úgy megtenni, hogy minden olyan metódushoz írunk visszaugró kódot, amely módosítja egy objektum állapotát. A cél nem az, hogy 100%-ra megbízható felügyelt kódot írjon, amely minden helyen helyreállítja a biztonsági mentési kóddal kapcsolatos hibákat. Ez ijesztő feladat lenne, kevés esély van a sikerre. A közös nyelvi futtatókörnyezet (CLR) nem tud elég erős garanciát nyújtani a felügyelt kódhoz, hogy a tökéletes kódírás megvalósítható legyen. Vegye figyelembe, hogy a ASP.NET ellentétben az SQL Server csak egy olyan folyamatot használ, amelyet nem lehet újrahasznosítani anélkül, hogy egy adatbázist elfogadhatatlanul hosszú időre leállítani kellene.

Mivel ezek a gyengébb garanciák és egyetlen folyamaton futnak, a megbízhatóság a szálak megszüntetésén vagy az alkalmazástartományok szükség esetén történő újrahasznosításán alapul, és óvintézkedéseket kell tennie annak érdekében, hogy az operációs rendszer erőforrásai, például a fogantyúk vagy a memória ne szivárogjanak ki. Még ennél az egyszerűbb megbízhatósági korlátozásnál is jelentős megbízhatósági követelmény áll fenn:

  • Soha ne szivárogtasd ki az operációs rendszer erőforrásait.

  • Azonosítsa a CLR minden űrlapjának összes felügyelt zárolását.

  • Soha ne szakítsa meg az alkalmazások közötti megosztott állapotot, így az AppDomain újrahasznosítás zökkenőmentesen működik.

Bár elméletileg lehetséges felügyelt kódokat írni, hogy kezelni tudják ThreadAbortException, StackOverflowExceptionés OutOfMemoryException kivételeket, elvárják, hogy a fejlesztők ilyen robusztus kódot írjanak egy teljes alkalmazáson keresztül, ésszerűtlen. Emiatt a sávon kívüli kivételek a végrehajtási szál leállítását eredményezik; és ha a megszakított szál megosztott állapotot szerkesztett, amelyet az határozhat meg, hogy a szál rendelkezik-e zárolással, akkor a rendszer eltávolítja a AppDomain szálat. Ha egy megosztott állapotot szerkesztő metódus leáll, az állapot sérült lesz, mert nem lehet megbízható háttérkódot írni a megosztott állapot frissítéséhez.

A .NET-keretrendszer 2.0-s verziójában az egyetlen megbízható gazdagép az SQL Server. Ha a szerelvény sql serveren fog futni, akkor a szerelvény minden részén végezze el a megbízhatósági munkát, még akkor is, ha az adatbázisban való futtatáskor bizonyos funkciók le vannak tiltva. Erre azért van szükség, mert a kódelemző motor a szerelvény szintjén vizsgálja a kódot, és nem tudja megkülönböztetni a letiltott kódot. Az SQL Server másik programozási szempontja, hogy az SQL Server egy folyamat alatt futtat mindent, és AppDomain az újrahasznosítás az összes erőforrás, például a memória és az operációs rendszer fogópontjainak tisztítására szolgál.

A háttérkód véglegesítőitől, destruktoraitól vagy try/finally blokkjaitól nem függhet. Lehet, hogy megszakadnak, vagy nem hívják őket.

Az aszinkron kivételek nem várt helyeken, esetleg minden gépi utasításban előfordulhatnak: ThreadAbortException, StackOverflowExceptionés OutOfMemoryException.

A felügyelt szálak nem feltétlenül Win32-szálak az SQL-ben; lehet, hogy rostok.

A folyamatszintű vagy az alkalmazásközi megosztott tartomány megosztott állapota rendkívül nehéz biztonságosan módosítani, és lehetőség szerint kerülni kell.

A memóriakihasználtság nem ritka az SQL Serverben.

Ha az SQL Serveren üzemeltetett kódtárak nem frissítik megfelelően a megosztott állapotukat, nagy a valószínűsége annak, hogy a kód nem áll helyre az adatbázis újraindításáig. Emellett bizonyos szélsőséges esetekben előfordulhat, hogy ez az SQL Server-folyamat meghiúsulását okozhatja, ami az adatbázis újraindítását okozhatja. Az adatbázis újraindítása leállhat egy webhelyen, vagy hatással lehet a vállalati műveletekre, és ronthatja a rendelkezésre állást. Az operációs rendszer erőforrásainak, például a memóriának vagy a leíróknak a lassú kiszivárgása miatt a kiszolgáló végül sikertelen lesz a kiosztási leírók kiosztásában, és nincs lehetőség a helyreállításra, vagy előfordulhat, hogy a kiszolgáló lassan romlik a teljesítményben, és csökkenti az ügyfél alkalmazás rendelkezésre állását. Egyértelműen el szeretnénk kerülni ezeket a forgatókönyveket.

Ajánlott eljárások szabályai

A bevezetés arra összpontosított, hogy a kiszolgálón futó felügyelt kód kódvizsgálatának mit kell elkapnia a keretrendszer stabilitásának és megbízhatóságának növelése érdekében. Ezek az ellenőrzések általában jó gyakorlatnak számítanak, és abszolút kötelező a kiszolgálón.

A zárolt vagy erőforrás-korlátozásokkal szemben az SQL Server megszakít egy szálat, vagy megszakít egy AppDomain. Ilyen esetben a rendszer csak a korlátozott végrehajtási régióban (CER) lévő biztonsági mentési kódot futtatja.

Az erőforrásszivárgások elkerülése a Széf Handle használatával

Kipakolás esetén AppDomain nem függhet finally a blokkoktól vagy a véglegesítőktől, ezért fontos, hogy az összes operációsrendszer-erőforrás-hozzáférést az osztályon IntPtrkeresztül elvonja ahelyettSafeHandle, hogy , HandleRefvagy hasonló osztályokat hoz létre. Ez lehetővé teszi a CLR számára, hogy nyomon kövesse és bezárja a lebontás esetén is AppDomain használt fogópontokat. SafeHandle egy kritikus döntőst használ, amelyet a CLR mindig futtat.

Az operációs rendszer leírója a biztonságos leíróban lesz tárolva a létrehozásuk pillanatától a kiadásáig. Nincs olyan ablak, amely során előfordulhat, ThreadAbortException hogy kiszivárog egy fogópont. A platformmeghívás emellett hivatkozni fog a fogópontra, amely lehetővé teszi a leíró élettartamának szoros nyomon követését, megakadályozva a versenyfeltételek közötti Dispose biztonsági problémát és a fogópontot jelenleg használó metódust.

A legtöbb osztálynak, amely jelenleg rendelkezik véglegesítővel az operációs rendszer leírójának egyszerű törléséhez, már nem lesz szüksége a véglegesítőre. Ehelyett a véglegesítő a SafeHandle származtatott osztályban lesz.

Vegye figyelembe, hogy SafeHandle ez nem helyettesíti a IDisposable.Dispose. Az operációs rendszer erőforrásainak explicit módon történő ártalmatlanítása továbbra is lehetséges erőforrás-versengés és teljesítménybeli előnyök. Ne feledje, hogy finally az erőforrásokat explicit módon megsemmisítő blokkok végrehajtása nem feltétlenül fejeződik be.

SafeHandle Lehetővé teszi saját metódus implementálását ReleaseHandle , amely elvégzi a leíró felszabadítása érdekében végzett munkát, például az állapot átadását egy operációs rendszer kezelőjének felszabadító rutinjára vagy egy hurokban lévő fogópontok felszabadítására. A CLR garantálja, hogy ez a módszer fut. A végrehajtás szerzőjének ReleaseHandle feladata annak biztosítása, hogy a kezelő minden körülmények között szabadon legyen bocsátva. Ennek elmulasztása a fogópont kiszivárgását okozza, ami gyakran a fogóponthoz társított natív erőforrások kiszivárgását eredményezi. Ezért kritikus fontosságú a származtatott osztályok strukturálása SafeHandle , hogy a ReleaseHandle megvalósításhoz ne legyen szükség olyan erőforrások lefoglalására, amelyek esetleg nem érhetők el a meghívás időpontjában. Vegye figyelembe, hogy az olyan metódusok meghívása megengedett, amelyek a végrehajtás során ReleaseHandle meghiúsulhatnak, feltéve, hogy a kód képes kezelni az ilyen hibákat, és a natív leíró kiadására vonatkozó szerződést teljesíteni. Hibakeresési célokra olyan visszatérési értékkel rendelkezikBoolean, amely akkor állítható befalse, ReleaseHandle ha olyan katasztrofális hiba történik, amely megakadályozza az erőforrás kiadását. Ha engedélyezve van, aktiválja a releaseHandleFailed MDA-t, hogy segítsen a probléma azonosításában. Ez semmilyen más módon nem befolyásolja a futtatókörnyezetet; ReleaseHandle nem lesz ismét meghívva ugyanahhoz az erőforráshoz, ezért a leíró kiszivárog.

SafeHandle bizonyos kontextusokban nem megfelelő. Mivel a ReleaseHandle metódus egy véglegesítő szálon GC futtatható, az adott szálon felszabadítandó fogópontok ne legyenek becsomagolva.SafeHandle

A futtatókörnyezet hívható burkolói (RCW-k) további kód nélkül tisztíthatók a CLR-sel. A platformhívást használó és a COM-objektumokat egy vagy többként IUnknown*IntPtrkezelő kód esetében a kódot újra kell írni egy RCW használatához. SafeHandle lehet, hogy nem megfelelő ehhez a forgatókönyvhöz, mert előfordulhat, hogy egy nem felügyelt kiadási módszer visszahívja a felügyelt kódba.

Kódelemzési szabály

Az operációs rendszer erőforrásainak beágyazására használható SafeHandle . Ne használjon vagy ne írjon HandleRef be típusú IntPtrmezőket.

Győződjön meg arról, hogy a véglegesítőknek nem kell futniuk, hogy megakadályozzák az operációs rendszer erőforrásainak kiszivárgását

Alaposan tekintse át a véglegesítőket, hogy még ha nem is futnak is, ne szivárogjon ki egy kritikus operációsrendszer-erőforrás. A normál AppDomain kiürítéstől eltérően, ha az alkalmazás állandó állapotban fut, vagy amikor egy kiszolgáló, például az SQL Server leáll, az objektumok nem lesznek véglegesítve a hirtelen AppDomain kiürítés során. Győződjön meg arról, hogy az erőforrások nem szivárognak ki hirtelen kiürítés esetén, mivel az alkalmazás helyessége nem garantálható, de a kiszolgáló integritását úgy kell fenntartani, hogy nem szivárognak ki az erőforrások. Az operációs rendszer erőforrásainak felszabadítására használható SafeHandle .

Győződjön meg arról, hogy a záradékoknak nem kell futniuk az operációs rendszer erőforrásainak kiszivárgásának megakadályozása érdekében

finally a záradékok nem garantáltan a CER-en kívül futnak, így a kódtár-fejlesztőknek nem kell kódra támaszkodniuk egy finally blokkon belül a nem felügyelt erőforrások felszabadításához. A használat SafeHandle az ajánlott megoldás.

Kódelemzési szabály

Az operációs rendszer erőforrásainak tisztítására használható SafeHandle ahelyett, hogy Finalizea . Ne használja IntPtr; erőforrások beágyazására használható SafeHandle . Ha a végső záradéknak futnia kell, helyezze el egy CER-ben.

Minden zárolásnak át kell haladnia a meglévő felügyelt zárolási kódon

A CLR-nek tudnia kell, hogy a kód mikor van zárolva, hogy tudja, hogy a AppDomain szál megszakítása helyett inkább bontsa le a kódot. A szál megszakítása veszélyes lehet, mivel a szál által kezelt adatok inkonzisztens állapotban maradhatnak. Ezért az egésznek AppDomain újra kell hasznosítania. A zárolás azonosításának elmulasztásának következményei lehetnek holtpontok vagy helytelen eredmények. Használja a metódusokat BeginCriticalRegion , és EndCriticalRegion azonosítsa a zárolási régiókat. Ezek statikus metódusok az Thread osztályon, amelyek csak az aktuális szálra vonatkoznak, így megakadályozható, hogy az egyik szál szerkessze a másik szál zárolási számát.

Enter és Exit ezt a CLR-értesítést beépítetten kell használnia, ezért ajánlott a használatuk, valamint a zárolási utasítás használata, amely ezeket a módszereket használja.

Más zárolási mechanizmusok, például a spinzárak, és AutoResetEvent ezeket a metódusokat kell meghívni, hogy értesítsék a CLR-t egy kritikus szakasz megadásáról. Ezek a módszerek nem zárnak; tájékoztatják a CLR-t, hogy a kód egy kritikus szakaszban fut, és a szál megszakítása inkonzisztens állapotot hagyhat. Ha saját zárolástípust (például egyéni ReaderWriterLock osztályt) definiált, használja ezeket a zárolásszám-metódusokat.

Kódelemzési szabály

Jelölje meg és azonosítsa az összes zárolást a BeginCriticalRegion és EndCriticalRegiona . Ne használja, Incrementés Decrement ne használja CompareExchangea hurkot. Ne kezdeményezz platformhívást ezen módszerek Win32-variánsaihoz. Ne használja Sleep hurkokban. Ne használjon illékony mezőket.

A törlési kódnak végre vagy fogási blokkban kell lennie, nem követve a fogást

A törlési kódnak soha nem szabad követnie egy blokkot catch , hanem magában finally a blokkban vagy a catch blokkban kell lennie. Ez egy normális jó gyakorlat. A finally blokkok általában előnyben részesítettek, mert ugyanazt a kódot futtatják, mind kivétel esetén, mind pedig try a blokk végének szokásos észlelésekor. Egy váratlan kivétel (például egy ThreadAbortException) esetén a törlési kód nem fog futni. A nem felügyelt erőforrásokat, amelyeket egy finally adott helyen tisztítana meg, ideális esetben be kell burkolni a SafeHandle szivárgások elkerülése érdekében. Vegye figyelembe, hogy a C# using kulcsszó hatékonyan használható az objektumok, köztük a fogópontok megsemmisítésére.

Bár AppDomain az újrahasznosítás megtisztíthatja az erőforrásokat a véglegesítő szálon, még mindig fontos, hogy a tisztítási kódot a megfelelő helyre helyezze. Vegye figyelembe, hogy ha egy szál aszinkron kivételt kap zárolás nélkül, a CLR megpróbálja megszüntetni magát a szálat anélkül, hogy újra kellene hasznosítaniuk a AppDomainszálat. Ha az erőforrásokat hamarabb, mint később megtisztítják, az több erőforrás elérhetővé tételével és az élettartam jobb kezelésével segít. Ha nem zár be explicit módon egy leírót egy fájlhoz valamilyen hibakód elérési útján, akkor várja meg, amíg a SafeHandle véglegesítő megtisztítja azt, a kód következő futtatásakor előfordulhat, hogy nem sikerül elérnie ugyanazt a fájlt, ha a véglegesítő még nem futott. Ezért a törlési kód meglétének és megfelelő működésének biztosítása segít a hibák utáni helyreállításban, még akkor is, ha ez nem feltétlenül szükséges.

Kódelemzési szabály

Törölje a kódot, miután catch egy finally blokkban kell lennie. Hívásokat kezdeményezhet a végső blokkban való megsemmisítéshez. catch blokkok véget kell vetni egy dobás vagy újra. Bár vannak kivételek, például olyan kód, amely észleli, hogy létre lehet-e hozni egy hálózati kapcsolatot, ahol nagy számú kivételt kaphat, minden olyan kódnak, amely normál körülmények között több kivétel elfogását igényli, jeleznie kell, hogy a kódot tesztelni kell annak ellenőrzéséhez, hogy sikeres lesz-e.

Az alkalmazástartományok közötti folyamatszintű mutable megosztott állapotot meg kell szüntetni, vagy korlátozott végrehajtási régiót kell használni

A bevezetőben leírtak szerint nagyon nehéz lehet olyan felügyelt kódot írni, amely megbízható módon figyeli a folyamatszintű megosztott állapotot az alkalmazástartományokban. A folyamatszintű megosztott állapot bármilyen adatstruktúra, amelyet az alkalmazástartományok között osztanak meg, akár Win32-kódban, akár a CLR-ben, akár felügyelt kódban, újraírással. A megosztott mutable állapotokat nagyon nehéz helyesen írni felügyelt kódba, és a statikus megosztott állapotok csak nagy körültekintéssel végezhetők el. Ha folyamatszintű vagy gépszintű megosztott állapottal rendelkezik, keressen valamilyen módot a megosztott állapot eltávolítására vagy a megosztott állapot védelmére egy korlátozott végrehajtási régió (CER) használatával. Vegye figyelembe, hogy a nem azonosított és kijavított megosztott állapotú kódtárak olyan gazdagépet okozhatnak, mint például az SQL Server, amely tiszta AppDomain törlést igényel az összeomláshoz.

Ha a kód COM-objektumot használ, ne ossza meg ezt a COM-objektumot az alkalmazástartományok között.

A zárolások nem működnek folyamatszintű vagy alkalmazástartományok között.

Korábban a Enter zárolási utasítást globális folyamatzárak létrehozására használták. Ez például akkor fordul elő, ha agilis osztályokon AppDomain , például Type nem megosztott szerelvényekből, objektumokból, Thread internált sztringekből származó példányok, valamint az alkalmazástartományok között megosztott egyes sztringek remoting használatával vannak zárolva. Ezek a zárolások már nem folyamatszintűek. A folyamatszintű alkalmazástartomány-zárolás jelenlétének azonosításához állapítsa meg, hogy a zároláson belüli kód külső, tartós erőforrást, például lemezen lévő fájlt vagy esetleg adatbázist használ-e.

Vegye figyelembe, hogy a zárolás egy AppDomain adott tartományon belüli rögzítése problémákat okozhat, ha a védett kód külső erőforrást használ, mert a kód egyszerre több alkalmazástartományban is futhat. Ez problémát jelenthet, ha egy naplófájlba ír, vagy egy szoftvercsatornához köti a teljes folyamatot. Ezek a módosítások azt jelentik, hogy a felügyelt kód használatával nem lehet egyszerűen lekérni egy folyamat-globális zárolást, kivéve egy elnevezett Mutex vagy Semaphore példány használatát. Hozzon létre olyan kódot, amely nem fut egyszerre két alkalmazástartományban, vagy használja az osztályokat vagy Semaphore az Mutex osztályokat. Ha a meglévő kód nem módosítható, ne használjon win32 nevű mutexet a szinkronizálás eléréséhez, mert a szálas módban való futtatás azt jelenti, hogy nem garantálható, hogy ugyanaz az operációsrendszer-szál lekér és felszabadít egy mutexet. A kódzárat úgy kell szinkronizálnia, hogy a CLR tudja, hogy nem felügyelt kóddal szinkronizálja a zárolást, hanem a felügyelt Mutex osztályt, vagy egy elnevezett, vagy egy Semaphore elnevezett ManualResetEventAutoResetEventosztályt kell használnia.

Zár(typeof(MyType)) elkerülése

A megosztott szerelvényekben lévő privát és nyilvános Type objektumok, az összes alkalmazástartományban megosztott kód egy példányával szintén problémákat tapasztalnak. Megosztott szerelvények esetén egy folyamatnak csak egy Type példánya van, ami azt jelenti, hogy több alkalmazástartomány ugyanazt a példányt Type használja. Egy példány zárolása Type olyan zárolást hoz létre, amely nem csak a teljes folyamatot érinti, hanem a AppDomainteljes folyamatot is. Ha valaki AppDomain zárol egy Type objektumot, akkor a szál hirtelen megszakad, az nem fogja feloldni a zárolást. Ez a zárolás ezt követően más alkalmazástartományok holtponthoz vezethetnek.

A statikus metódusok zárolásának jó módja, ha statikus belső szinkronizálási objektumot ad hozzá a kódhoz. Ez inicializálható az osztálykonstruktorban, ha van ilyen, de ha nem, akkor a következőképpen inicializálható:

private static Object s_InternalSyncObject;
private static Object InternalSyncObject
{
    get
    {
        if (s_InternalSyncObject == null)
        {
            Object o = new Object();
            Interlocked.CompareExchange(
                ref s_InternalSyncObject, o, null);
        }
        return s_InternalSyncObject;
    }
}

Ezt követően a zárolás során a InternalSyncObject tulajdonság használatával szerezze be a zároláshoz szükséges objektumot. Nem kell használnia a tulajdonságot, ha inicializálta a belső szinkronizálási objektumot az osztálykonstruktorban. A kettős ellenőrzés zár inicializálási kódjának a következő példához hasonlóan kell kinéznie:

public static MyClass SingletonProperty
{
    get
    {
        if (s_SingletonProperty == null)
        {
            lock(InternalSyncObject)
            {
                // Do not use lock(typeof(MyClass))
                if (s_SingletonProperty == null)
                {
                    MyClass tmp = new MyClass(…);
                    // Do all initialization before publishing
                    s_SingletonProperty = tmp;
                }
            }
        }
        return s_SingletonProperty;
    }
}

Megjegyzés a zárolásról (ez)

Általánosan elfogadható, hogy egy nyilvánosan elérhető objektumot zároljon. Ha azonban az objektum egy önálló objektum, amely egy teljes alrendszer holtpontját okozhatja, fontolja meg a fenti tervezési minta használatát is. Egy objektum zárolása SecurityManager például holtpontot okozhat az AppDomain egész AppDomain használhatatlanná tételében. Célszerű nem zárolni egy ilyen típusú, nyilvánosan elérhető objektumot. Az egyes gyűjtemények vagy tömbök zárolása azonban általában nem jelenthet problémát.

Kódelemzési szabály

Ne zárjon le olyan típusokat, amelyek alkalmazástartományokon keresztül használhatók, vagy amelyek nem rendelkeznek erős identitásérzékkel. Ne hívjon meg , Type, , , , ValueType, Threadvagy bármilyen objektumot, amely származikMarshalByRefObject. StringPropertyInfoMethodInfoEnter

GC eltávolítása. KeepAlive hívások

A meglévő kód jelentős része vagy nem használja KeepAlive , amikor szükséges, vagy akkor használja, ha az nem megfelelő. A konvertálás SafeHandleután az osztályoknak nem kell meghívniuk KeepAliveőket, feltéve, hogy nem rendelkeznek véglegesítővel, hanem az operációsrendszer-leírók véglegesítésére SafeHandle támaszkodnak. Bár a hívás megtartásának KeepAlive teljesítményköltsége elhanyagolható lehet, az a felfogás, hogy a hívás KeepAlive vagy szükséges, vagy elegendő egy olyan életen át tartó probléma megoldásához, amely esetleg már nem létezik, megnehezíti a kód karbantartását. A COM interop CLR hívható burkolóinak (RCW-k) KeepAlive használata esetén azonban a kód továbbra is kötelező.

Kódelemzési szabály

Eltávolítás KeepAlive.

A HostProtection attribútum használata

A HostProtectionAttribute (HPA) deklaratív biztonsági műveletek használatát biztosítja a gazdagépek védelmi követelményeinek meghatározásához, így a gazdagép megakadályozhatja, hogy a teljes mértékben megbízható kód meghívjon bizonyos metódusokat, amelyek nem megfelelőek az adott gazdagéphez, például Exit az SQL Serverhez.Show

A HPA csak azokat a nem felügyelt alkalmazásokat érinti, amelyek a közös nyelvi futtatókörnyezetet üzemeltetik, és gazdavédelmet implementálnak, például az SQL Servert. Alkalmazás esetén a biztonsági művelet egy hivatkozási igény létrehozását eredményezi az osztály vagy metódus által elérhetővé tett gazdagép-erőforrások alapján. Ha a kód egy ügyfélalkalmazásban vagy egy nem gazdagép által védett kiszolgálón fut, az attribútum "elpárolog"; a rendszer nem észleli, ezért nem alkalmazza.

Fontos

Ennek az attribútumnak az a célja, hogy a gazdagépspecifikus programozási modellre vonatkozó irányelveket kényszerítsen ki, nem pedig a biztonsági viselkedést. Bár a hivatkozási igény a programozási modell követelményeinek való megfelelés ellenőrzésére szolgál, ez HostProtectionAttribute nem biztonsági engedély.

Ha a gazdagép nem rendelkezik programozási modellre vonatkozó követelményekkel, a hivatkozási követelmények nem lépnek fel.

Ez az attribútum a következőket azonosítja:

  • Azok a metódusok vagy osztályok, amelyek nem felelnek meg a gazdagép programozási modelljének, de egyébként jóindulatúak.

  • Olyan metódusok vagy osztályok, amelyek nem felelnek meg a gazdagép programozási modelljének, és a kiszolgáló által felügyelt felhasználói kód destabilizálásához vezethetnek.

  • Olyan metódusok vagy osztályok, amelyek nem felelnek meg a gazdagép programozási modelljének, és maga a kiszolgálófolyamat destabilizálásához vezethet.

Feljegyzés

Ha olyan osztálytárat hoz létre, amelyet gazdagép által védett környezetben végrehajtható alkalmazásoknak kell meghívnia, ezt az attribútumot az erőforráskategóriákat közzétesző HostProtectionResource tagokra kell alkalmaznia. Az attribútummal rendelkező .NET-keretrendszer osztálytártagok csak az azonnali hívót ellenőrzik. A tártagnak ugyanúgy kell ellenőriznie az azonnali hívóját.

További információt a HPA-ról itt HostProtectionAttributetalál.

Kódelemzési szabály

Az SQL Server esetében a szinkronizálás vagy a szálkezelés bevezetéséhez használt összes módszert azonosítani kell a HPA-val. Ide tartoznak az állapotot megosztó, szinkronizált vagy külső folyamatokat kezelő metódusok. Az HostProtectionResource SQL Servert befolyásoló értékek a következőkSharedState: és ExternalProcessMgmtSynchronization. A hpA-nak azonban minden olyan módszert azonosítania kell, amely az HostProtectionResource SQL-t érintő erőforrásokat használ.

Ne tiltsa le határozatlan ideig a nem felügyelt kódban

A felügyelt kód helyett nem felügyelt kódban való blokkolás szolgáltatásmegtagadási támadást okozhat, mivel a CLR nem tudja megszakítani a szálat. A blokkolt szál megakadályozza, hogy a CLR kiürítse a AppDomainműveletet, legalábbis anélkül, hogy rendkívül veszélyes műveleteket végez. A Windows-szinkronizálás primitív használatának blokkolása egyértelmű példa arra, amit nem tudunk engedélyezni. Ha lehetséges, kerülni kell a szoftvercsatornán történő ReadFile hívás blokkolását – ideális esetben a Windows API-nak biztosítania kell egy olyan mechanizmust, amely időtúllépést biztosít egy ilyen művelethez.

A natív hívásokat kezdeményező metódusoknak ideális esetben egy Win32-hívást kell használniuk ésszerű, véges időtúllépéssel. Ha a felhasználó megadhatja az időtúllépést, a felhasználónak nem szabad engedélyezni, hogy meghatározott biztonsági engedély nélkül végtelen időtúllépést adjon meg. Ha egy metódus több mint ~10 másodpercig blokkolni fog, akkor olyan verziót kell használnia, amely támogatja az időtúllépéseket, vagy további CLR-támogatásra van szüksége.

Íme néhány példa a problémás API-kra. A csövek (névtelenek és elnevezettek) időtúllépéssel hozhatók létre; a kódnak azonban gondoskodnia kell arról, hogy soha ne telefonáljon CreateNamedPipe , és WaitNamedPipe ne NMPWAIT_WAIT_FOREVER. Emellett váratlan blokkolás is előfordulhat, még ha időtúllépés is van megadva. A névtelen cső hívása WriteFile mindaddig blokkolódik, amíg az összes bájt meg nem íródik, vagyis ha a puffer olvasatlan adatokat tartalmaz, a WriteFile hívás addig blokkolódik, amíg az olvasó nem szabadít fel helyet a cső pufferében. A szoftvercsatornáknak mindig olyan API-t kell használniuk, amely tiszteletben tart egy időtúllépési mechanizmust.

Kódelemzési szabály

A nem felügyelt kódban időtúllépés nélkül történő blokkolás szolgáltatásmegtagadásos támadás. Ne végezzen platformhívási hívásokat a WaitForSingleObject, WaitForSingleObjectEx, , WaitForMultipleObjectsMsgWaitForMultipleObjectsés MsgWaitForMultipleObjectsEx. Ne használja a NMPWAIT_WAIT_FOREVER.

Sta-függő funkciók azonosítása

Azonosítsa a COM egyszálas apartmanokat (STA-kat) használó kódokat. Az STA-k le vannak tiltva az SQL Server-folyamatban. A teljesítményszámlálóktól vagy a vágólaptól függő CoInitializefunkciókat le kell tiltani az SQL Serveren belül.

Győződjön meg arról, hogy a véglegesítők nem okoznak szinkronizálási problémákat

A .NET-keretrendszer későbbi verzióiban több véglegesítőszál is létezhet, ami azt jelenti, hogy az azonos típusú különböző példányok véglegesítői egyszerre futnak. Nem kell teljesen szálbiztosnak lenniük; a szemétgyűjtő garantálja, hogy csak egy szál futtassa az adott objektumpéldány véglegesítőjét. A véglegesítőket azonban kódolt módon kell megadni, hogy elkerülje a versenyfeltételeket és a holtpontokat, amikor egyszerre futnak több különböző objektumpéldányon. Ha bármilyen külső állapotot használ, például naplófájlba ír, a véglegesítőben a szálkezeléssel kapcsolatos problémákat kell kezelni. Ne támaszkodjon a véglegesítésre a szálbiztonság érdekében. A véglegesítő szál állapotának tárolásához ne használjon helyi, felügyelt vagy natív szálat.

Kódelemzési szabály

A véglegesítőknek szinkronizálási problémáktól mentesnek kell lenniük. A véglegesítőben ne használjon statikus mutable állapotot.

Ha lehetséges, kerülje a nem felügyelt memóriát

A nem felügyelt memória kiszivároghat, akárcsak egy operációs rendszer leírója. Ha lehetséges, próbáljon meg memóriahasználatot használni a veremen a stackalloc vagy egy rögzített felügyelt objektum, például a rögzített utasítás vagy a GCHandle bájt[] használatával. A GC végül megtisztítja ezeket. Ha azonban nem felügyelt memóriát kell lefoglalnia, érdemes lehet egy olyan osztályt használnia, amelyből SafeHandle származik a memóriafoglalás burkolása.

Vegye figyelembe, hogy legalább egy eset SafeHandle nem megfelelő. A memóriát lefoglaló vagy szabad memóriát felszabadító COM-metódushívások esetében gyakori, hogy egy DLL-nek a memóriát egy másik DLL-en keresztül CoTaskMemAlloc kell lefoglalnia, és ezzel felszabadítja a memóriát CoTaskMemFree. Ezen helyek használata SafeHandle nem lenne megfelelő, mivel a nem felügyelt memória élettartamát a memória élettartamához próbálja kötni ahelyett SafeHandle , hogy a másik DLL szabályozná a memória élettartamát.

A fogás (kivétel) összes felhasználási módja áttekintése

Az összes kivételt egy adott kivétel helyett elkapó blokkok mostantól az aszinkron kivételeket is elkapják. Vizsgálja meg az összes catch(Exception) blokkot, és ne keressen olyan fontos erőforrás-kiadási vagy háttérkódot, amely kihagyható lenne, valamint a fogási blokkon belül esetleg helytelen viselkedést keres egy ThreadAbortException, StackOverflowExceptionvagy OutOfMemoryException. Vegye figyelembe, hogy lehetséges, hogy ez a kód naplózást végez, vagy feltételezi, hogy csak bizonyos kivételeket lát, vagy hogy amikor kivétel történik, az pontosan egy adott okból meghiúsult. Előfordulhat, hogy ezeket a feltételezéseket frissíteni kell a belefoglaláshoz ThreadAbortException.

Fontolja meg az összes olyan hely módosítását, amely az összes kivételt elfogja, hogy egy adott típusú kivételt kapjon, amelyet elvár, például sztringformázási FormatException módszerekből. Ez megakadályozza, hogy a fogási blokk váratlan kivételeken fusson, és a kód nem rejti el a hibákat a váratlan kivételek elfogásával. Általános szabályként soha ne kezeljen kivételt a kódtárkódban (a kivételt hívó kód a kód tervezési hibáját jelezheti). Bizonyos esetekben előfordulhat, hogy egy kivételt szeretne elkapni, és egy másik kivételtípust kell megadnia, hogy több adatot adjon meg. Ebben az esetben használjon beágyazott kivételeket, és tárolja a hiba valódi okát az InnerException új kivétel tulajdonságában.

Kódelemzési szabály

Tekintse át a felügyelt kód összes olyan fogási blokkját, amely az összes objektumot elfogja, vagy az összes kivételt elfogja. A C#-ban ez azt jelenti, hogy mind catch{} a catch(Exception){}. Fontolja meg, hogy a kivétel típusa nagyon specifikus legyen, vagy tekintse át a kódot, hogy ne működjön rosszul, ha váratlan kivételtípust kap.

Ne feltételezzük, hogy egy felügyelt szál Win32-szál – Ez egy szál

A felügyelt szál helyi tárolójának használata nem működik, de előfordulhat, hogy nem felügyelt helyi szálat használ, vagy feltételezi, hogy a kód újra fut az aktuális operációsrendszer-szálon. Ne módosítsa a beállításokat, például a szál területi beállítását. Ne hívjon vagy InitializeCriticalSectionCreateMutex platformon keresztül hívjon meg, mert a zárolásba belépő operációsrendszer-szálra is szükség van. Mivel rostok használata esetén ez nem történik meg, a Win32 kritikus szakaszai és a mutexek nem használhatók közvetlenül az SQL-ben. Vegye figyelembe, hogy a felügyelt Mutex osztály nem kezeli ezeket a szál-affinitási problémákat.

Az állapot nagy részét biztonságosan használhatja egy felügyelt Thread objektumon, beleértve a felügyelt szál helyi tárolóját és a szál aktuális felhasználói felületi kultúráját. Használhatja azt ThreadStaticAttributeis, amely egy meglévő statikus változó értékét csak az aktuális felügyelt szálon teszi elérhetővé (ez egy másik módszer a szálalapú helyi tárolásra a CLR-ben). A programozási modell okból nem módosíthatja a szál aktuális kultúráját az SQL-ben való futtatáskor.

Kódelemzési szabály

Az SQL Server szálas módban fut; ne használjon szál helyi tárolót. Ne hívja meg a platform a TlsAlloc, TlsFree, TlsGetValueés a TlsSetValue.

Az SQL Server kezelje a megszemélyesítést

Mivel a megszemélyesítés a szál szintjén működik, és az SQL szál módban futtatható, a felügyelt kód nem szabad megszemélyesíteni a felhasználókat, és nem szabad meghívni RevertToSelf.

Kódelemzési szabály

Hagyja, hogy az SQL Server kezelje a megszemélyesítést. Ne használja RevertToSelfa , ImpersonateAnonymousToken, DdeImpersonateClient, ImpersonateDdeClientWindow, ImpersonateLoggedOnUser, ImpersonateNamedPipeClient, ImpersonateSelf, RpcImpersonateClient, RpcRevertToSelf, RpcRevertToSelfEx, vagy SetThreadToken.

Ne hívja meg a szálat::Felfüggesztés

A szál felfüggesztése egyszerű műveletnek tűnhet, de holtpontot okozhat. Ha egy zárolást tartalmazó szálat egy második szál függeszt fel, majd a második szál megpróbálja ugyanazt a zárolást venni, holtpont jön létre. Suspend jelenleg zavarhatja a biztonságot, az osztály betöltését, az újrametszést és a tükrözést.

Kódelemzési szabály

Ne hívjon.Suspend Érdemes lehet inkább valós szinkronizálási primitívet használni, például egy Semaphore vagy ManualResetEvent .

Kritikus műveletek védelme korlátozott végrehajtási régiókkal és megbízhatósági szerződésekkel

Ha olyan összetett műveletet hajt végre, amely frissíti a megosztott állapotot, vagy determinisztikusan vagy teljes mértékben sikeresnek vagy teljes mértékben sikertelennek kell lennie, győződjön meg arról, hogy egy korlátozott végrehajtási régió (CER) védi. Ez garantálja, hogy a kód minden esetben fut, még egy hirtelen szál megszakítása vagy AppDomain hirtelen kipakolása is.

A CER egy adott try/finally blokk, amelyet közvetlenül a hívás PrepareConstrainedRegionselőz meg.

Ezzel arra utasítja az igény szerinti fordítót, hogy a blokk futtatása előtt készítse elő a végső blokk összes kódját try . Ez garantálja, hogy a végül blokkban lévő kód létre van hozva, és minden esetben futni fog. A CER-ben nem ritka, hogy üres try blokk van. A CER használata védelmet nyújt az aszinkron szál megszakításai és a memóriakivételek ellen. Tekintse meg ExecuteCodeWithGuaranteedCleanup a cer egy olyan formáját, amely emellett kezeli a verem túlcsordulását a rendkívül mély kódhoz.

Lásd még