Sicherheit und Racebedingungen
Ein weiteres Problemfeld besteht in der Möglichkeit, dass Sicherheitslücken durch Racebedingungen ausgenutzt werden. Diesbezügliche Probleme können auf verschiedene Weise auftreten. In den folgenden untergeordneten Themen werden einige der gravierenden Fehler erläutert, die von Entwicklern vermieden werden müssen.
Racebedingungen in der Dispose-Methode
Wenn die Dispose-Methode einer Klasse (weitere Informationen hierzu unter Garbage Collection) nicht synchronisiert wird, kann Bereinigungscode in Dispose mehrmals ausgeführt werden, wie im folgenden Beispiel veranschaulicht.
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 Implementierung von Dispose nicht synchronisiert wird, kann Cleanup
u. U. erst durch einen Thread und anschließend durch einen zweiten Thread aufgerufen werden, bevor _myObj
auf null festgelegt wird. Ob dies ein Sicherheitsproblem darstellt, hängt von den Ereignissen während der Ausführung des Cleanup
-Codes ab. Ein ernstes Problem bei nicht synchronisierten Implementierungen von Dispose stellt die Verwendung von Ressourcenhandles (z. B. Dateien) dar. Eine falsche Freigabe kann die Verwendung des falschen Handles bewirken. Dies führt häufig zu Sicherheitsrisiken.
Racebedingungen in Konstruktoren
In einigen Anwendungen können möglicherweise andere Threads auf Klassenmember zugreifen, bevor ihre Klassenkonstruktoren vollständig ausgeführt wurden. Sie müssen alle Klassenkonstruktoren überprüfen, um sicherzustellen, dass bei einem solchen Ereignis keine Sicherheitsprobleme auftreten. Synchronisieren Sie ggf. die Threads.
Racebedingungen mit zwischengespeicherten Objekten
Code, der Sicherheitsinformationen zwischenspeichert oder die Assert-Operation für die Codezugriffssicherheit verwendet, kann ebenso anfällig für Racebedingungen sein, wenn andere Teile der Klasse nicht ordnungsgemäß synchronisiert werden. Dies wird im folgenden Beispiel veranschaulicht.
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 weitere Pfade zu DoOtherWork
vorhanden sind, die von einem anderen Thread mit demselben Objekt aufgerufen werden können, kann eine Forderung durch einen nicht vertrauenswürdigen Aufrufer umgangen werden.
Wenn der Code Sicherheitsinformationen zwischenspeichert, müssen Sie unbedingt eine Überprüfung auf dieses Risiko durchführen.
Racebedingungen in Finalizern
Racebedingungen können auch in einem Objekt auftreten, das auf eine statische oder nicht verwaltete Ressource verweist, die anschließend in seinem Finalizer freigegeben wird. Wenn mehrere Objekte eine Ressource gemeinsam verwenden und diese im Finalizer einer Klasse bearbeitet wird, müssen die Objekte jeglichen Zugriff auf diese Ressource synchronisieren.