Partilhar via


Segurança e Condições de Corrida

Outra área de preocupação é o potencial de falhas de segurança exploradas pelas condições de corrida. Há várias maneiras pelas quais isso pode acontecer. Os subtópicos a seguir descrevem algumas das principais armadilhas que o desenvolvedor deve evitar.

Condições de Corrida no Método de Descarte

Se o método Dispose de uma classe (para obter mais informações, consulte Garbage Collection) não estiver sincronizado, é possível que o código de limpeza dentro de Dispose possa ser executado mais de uma vez, conforme mostrado no exemplo a seguir.

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;  
    }  
}  

Como essa implementação Dispose não está sincronizada, é possível Cleanup ser chamado primeiro por um thread e, em seguida, um segundo thread antes _myObj é definido como null. Se isso é uma preocupação de segurança depende do que acontece quando o Cleanup código é executado. Um grande problema com implementações Dispose não sincronizadas envolve o uso de identificadores de recursos, como arquivos. O descarte inadequado pode fazer com que a alça errada seja utilizada, o que muitas vezes resulta em vulnerabilidades de segurança.

Condições de Concorrência em Construtores

Em alguns aplicativos, pode ser possível que outros threads acessem membros de classe antes que seus construtores de classe tenham sido completamente executados. Você deve revisar todos os construtores de classe para certificar-se de que não há problemas de segurança, se isso acontecer, ou sincronizar threads, se necessário.

Condições de corrida com objetos armazenados em cache

O código que armazena em cache informações de segurança ou usa a operação Assert de segurança de acesso ao código também pode ser vulnerável a condições de corrida se outras partes da classe não estiverem adequadamente sincronizadas, conforme mostrado no exemplo a seguir.

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();  
    }  
}  

Se há outros caminhos para DoOtherWork que possam ser invocados a partir de outra thread com o mesmo objeto, um chamador não confiável pode escapar de uma verificação de permissão.

Se o seu código armazenar informações de segurança em cache, certifique-se de que o analisa para esta vulnerabilidade.

Condições de Corrida em Finalizadores

As condições de corrida também podem ocorrer em um objeto que faz referência a um recurso estático ou não gerenciado que ele libera em seu finalizador. Se vários objetos compartilharem um recurso que é manipulado no finalizador de uma classe, os objetos devem sincronizar todo o acesso a esse recurso.

Ver também