Sdílet prostřednictvím


Podmínky zabezpečení a závodní podmínky

Další oblastí zájmu je potenciál bezpečnostních otvorů využívaných podmínkami závodu. Existuje několik způsobů, jak k tomu může dojít. Podtémata, která následují, popisují některá hlavní úskalí, kterým by se měl vývojář vyhnout.

Konkurenční podmínky v metodě Dispose

Pokud metoda Dispose třídy (další informace, viz uvolňování paměti) není synchronizována, je možné, že kód čištění uvnitř Dispose lze spustit více než jednou, jak je znázorněno v následujícím příkladu.

Sub Dispose()  
    If Not (myObj Is Nothing) Then  
       Cleanup(myObj)  
       myObj = Nothing  
    End If  
End Sub  
void Dispose()
{  
    if (myObj != null)
    {  
        Cleanup(myObj);  
        myObj = null;  
    }  
}  

Vzhledem k tomu, že tato implementace Dispose není synchronizována, je možné, že ji nejprve volá první vlákno a poté druhé vlákno, předtím než je Cleanup nastaveno na _myObj. To, jestli se jedná o bezpečnostní problém, závisí na tom, co se stane, když Cleanup se kód spustí. Hlavním problémem nesynchronizovaných implementací Dispose je používání popisovačů prostředků, jako jsou soubory. Nesprávné odstranění může způsobit použití nesprávného popisovače, což často vede k ohrožením zabezpečení.

Konkurenční podmínky v konstruktorech

V některých aplikacích může být možné, aby ostatní vlákna přistupovala ke členům třídy před tím, než se jejich konstruktory třídy úplně spustily. Měli byste zkontrolovat všechny konstruktory tříd, abyste měli jistotu, že neexistují žádné problémy se zabezpečením, pokud k tomu dojde, nebo v případě potřeby synchronizujte vlákna.

Podmínky časování s objekty uloženými v mezipaměti

Kód, který ukládá informace o zabezpečení do mezipaměti nebo používá operaci Assert zabezpečení přístupu kódu, může být také zranitelný vůči časovacím podmínkám, pokud ostatní části třídy nejsou správně synchronizovány, jak je znázorněno v následujícím příkladu.

Sub SomeSecureFunction()  
    If SomeDemandPasses() Then  
        fCallersOk = True  
        DoOtherWork()  
        fCallersOk = False  
    End If  
End Sub  
  
Sub DoOtherWork()  
    If fCallersOK Then  
        DoSomethingTrusted()  
    Else  
        DemandSomething()  
        DoSomethingTrusted()  
    End If  
End Sub  
void SomeSecureFunction()
{  
    if (SomeDemandPasses())
    {  
        fCallersOk = true;  
        DoOtherWork();  
        fCallersOk = false;  
    }  
}  
void DoOtherWork()
{  
    if (fCallersOK)
    {  
        DoSomethingTrusted();  
    }  
    else
    {  
        DemandSomething();  
        DoSomethingTrusted();  
    }  
}  

Pokud existují další cesty k DoOtherWork, které lze volat z jiného vlákna se stejným objektem, může nedůvěryhodný volající překonat požadavek.

Pokud váš kód ukládá informace o zabezpečení do mezipaměti, ujistěte se, že je zkontrolujete pro tuto chybu zabezpečení.

Podmínky závodu v finalizátorech

K závodním podmínkám může dojít také v objektu, který odkazuje na statický nebo nespravovaný prostředek, který pak uvolní ve svém finalizéru. Pokud více objektů sdílí prostředek, který je manipulován s finalizátorem třídy, musí objekty synchronizovat veškerý přístup k danému prostředku.

Viz také