Sicherheit und Racebedingungen
Ein weiterer Problembereich ist das Potenzial für Sicherheitslücken, die durch Racebedingungen ausgenutzt werden. Dies kann auf verschiedene Arten erfolgen. Die nachfolgenden Unterthemen beschreiben einige der wichtigsten Probleme, die Entwickler vermeiden müssen.
Racebedingungen in der Dispose-Methode
Wenn die Dispose-Methode einer Klasse (weitere Informationen finden Sie unter Garbage Collection) nicht synchronisiert ist, kann der Bereinigungscode in Dispose u. U. mehr als einmal ausgeführt werden kann, wie im folgenden Beispiel gezeigt.
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;
}
}
Da diese Dispose-Implementierung nicht synchronisiert ist, kann Cleanup
zuerst von einem und dann von einem zweiten Thread aufgerufen werden, bevor _myObj
auf NULL festgelegt wird. Ob dies ein Sicherheitsproblem ist, hängt davon ab, was geschieht, wenn der Cleanup
-Code ausgeführt wird. Eines der größeren Probleme bei nicht synchronisierten Dispose-Implementierungen ist die Verwendung von Ressourcenhandles wie Dateien. Eine unsachgemäße Löschung kann dazu führen, dass der falsche Handle verwendet wird, was häufig zu Sicherheitsrisiken führt.
Racebedingungen in Konstruktoren
In einigen Anwendungen können andere Threads u. U. auf Klassenmember zugreifen, bevor die Klassenkonstruktoren vollständig ausgeführt wurden. Überprüfen Sie alle Klassenkonstruktoren, um sicherzustellen, dass es in diesem Fall keine Sicherheitsprobleme gibt. Alternativ können Sie die Threads bei Bedarf synchronisieren.
Racebedingungen mit zwischengespeicherten Objekten
Code, der Sicherheitsinformationen zwischenspeichert oder den Assert-Vorgang für die Codezugriffssicherheit verwendet, kann ebenfalls anfällig für Racebedingungen sein, wenn andere Teile der Klasse nicht entsprechend synchronisiert sind, wie im folgenden Beispiel gezeigt.
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();
}
}
Wenn andere Pfade zu DoOtherWork
vorhanden sind, die von einem anderen Thread mit demselben Objekt aufgerufen werden können, kann ein nicht vertrauenswürdiger Aufrufer eine Anforderung umgehen.
Wenn Ihr Code Sicherheitsinformationen zwischenspeichert, stellen Sie sicher, dass er nicht für dieses Problem anfällig ist.
Racebedingungen in Finalizern
Racebedingungen können auch in einem Objekt auftreten, das auf eine statische oder nicht verwaltete Ressource verweist, die dann in ihrem Finalizer freigegeben wird. Wenn mehrere Objekte eine Ressource gemeinsam nutzen, die im Finalizer einer Klasse bearbeitet wird, müssen die Objekte den gesamten Zugriff auf diese Ressource synchronisieren.