A computação distribuída consiste em tempo e estado. Isto é, para que mais de um componente se comunique, é necessário compartilhar o estado, o que exige tempo.
A maioria dos programadores antropomorfiza seu trabalho. Eles enxergam um thread de controle executando todo o programa da mesma forma como enxergariam a si mesmos fazendo o trabalho inteiro por conta própria. Computadores modernos, entretanto, alternam entre tarefas com muita rapidez e, em sistemas multi-core, multi-CPU ou distribuídos, dois eventos podem ocorrer exatamente ao mesmo tempo. Defeitos rapidamente são postos nas lacunas entre o modelo do programador de como um programa é executado e o que ocorre na realidade. Esses defeitos estão relacionados com interações inesperadas entre threads, processos, tempo e informações. Essas interações ocorrem por meio de estados compartilhados: semáforos, variáveis, o sistema de arquivos e, basicamente, todas as coisas capazes de armazenar informações.
HttpSession
pode prejudicar a confiabilidade do aplicativo.HttpSession
em várias JVMs de forma que, se uma JVM se tornar indisponível, outra poderá entrar e tomar o seu lugar sem interromper o fluxo do aplicativo.Serializable
.
public class DataGlob {
String globName;
String globValue;
public void addToSession(HttpSession session) {
session.setAttribute("glob", this);
}
}
block.timestamp
ou block.number
como um proxy para o tempo.block.timestamp
ou block.number
são frequentemente usados por desenvolvedores para acionar eventos dependentes de tempo, no entanto, esses valores geralmente dão uma noção de tempo que geralmente não é segura para uso.block.timestamp
não é confiável e, na pior das hipóteses, mineradores mal-intencionados poderão alterar o carimbo de data/hora de seus blocos se perceberem uma vantagem em fazê-lo.block.number
, embora seja possível prever o tempo entre os blocos (aproximadamente 14 segundos), os tempos dos blocos não são constantes e podem variar dependendo da atividade da rede. Isso torna block.number
não confiável para cálculos relacionados ao tempo.block.number
para desbloquear fundos após um determinado período.
function withdraw() public {
require(users[msg.sender].amount > 0, 'no amount locked');
require(block.number >= users[msg.sender].unlockBlock, 'lock period not over');
uint amount = users[msg.sender].amount;
users[msg.sender].amount = 0;
(bool success, ) = msg.sender.call.value(amount)("");
require(success, 'transfer failed');
}
...
var authenticated = true;
...
database_connect.query('SELECT * FROM users WHERE name == ? AND password = ? LIMIT 1', userNameFromUser, passwordFromUser, function(err, results){
if (!err && results.length > 0){
authenticated = true;
}else{
authenticated = false;
}
});
if (authenticated){
//do something privileged stuff
authenticatedActions();
}else{
sendUnathenticatedMessage();
}
true
, caso contrário, false
. Infelizmente, uma vez que o retorno de chamada é bloqueado por E/S, ele será executado de forma assíncrona e poderá ser executado após a verificação para if (authenticated)
, e, como o padrão era verdadeiro, ele vai para a if-statement quer o o usuário esteja realmente autenticado ou não.
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(Environment.getExternalStorageDirectory() + "/download/" + "app.apk")), "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
setuid root
. O programa executa certas operações de arquivo em nome de usuários sem privilégios e usa verificações de acesso para garantir que ele não use seus privilégios de root para executar operações que não deveriam estar disponíveis ao usuário atual. O programa usa a chamada de sistema access()
para verificar se a pessoa que está executando o programa tem permissão para acessar o arquivo especificado antes de abri-lo e executar as operações necessárias.
if (!access(file,W_OK)) {
f = fopen(file,"w+");
operate(f);
...
}
else {
fprintf(stderr,"Unable to open file %s.\n",file);
}
access()
se comporta conforme o esperado, retornando 0
quando o usuário que está executando o programa tem as permissões necessárias para gravar no arquivo e -1 em outros casos. No entanto, como access()
e fopen()
operam ambos em nomes de arquivo em vez de em identificadores de arquivo, não há nenhuma garantia de que a variável file
ao ser transmitida para fopen()
ainda faça referência ao mesmo arquivo no disco de quando ela foi transmitida para access()
. Se um invasor substituir file
após a chamada para access()
por um link simbólico para um arquivo diferente, o programa usará seus privilégios de root para operar nesse arquivo, mesmo que este seja um arquivo que o invasor seria incapaz de modificar em outras circunstâncias. Ao enganar o programa a ponto de fazer com que ele realizasse uma operação que de outra forma seria inadmissível, o invasor obteve privilégios elevados.root
. Se o aplicativo for capaz de realizar qualquer operação que o invasor de outra forma não teria permissão para realizar, então ele será um possível alvo.
fd = creat(FILE, 0644); /* Create file */
if (fd == -1)
return;
if (chown(FILE, UID, -1) < 0) { /* Change file owner */
...
}
chown()
seja igual ao arquivo criado pela chamada para creat()
, mas isso não é necessariamente o caso. Como chown()
opera em um nome de arquivo e não em um identificador de arquivo, um invasor pode ser capaz de substituir o arquivo por um link para um arquivo que ele não possui. Dessa maneira, a chamada para chown()
daria ao invasor a posse sobre o arquivo vinculado.CBL_CHECK_FILE_EXIST
para verificar se o arquivo existe antes de criar um e executa as operações necessárias.
CALL "CBL_CHECK_FILE_EXIST" USING
filename
file-details
RETURNING status-code
END-CALL
IF status-code NOT = 0
MOVE 3 to access-mode
MOVE 0 to deny-mode
MOVE 0 to device
CALL "CBL_CREATE_FILE" USING
filename
access-mode
deny-mode
device
file-handle
RETURNING status-code
END-CALL
END-IF
CBL_CHECK_FILE_EXIST
comporta-se como esperado e retorna um valor não zero, indicando que o arquivo não existe. Entretanto, como tanto CBL_CHECK_FILE_EXIST
quanto CBL_CREATE_FILE
operam de acordo com nomes de arquivo, em vez de identificadores de arquivo, não há garantia de que a variável filename
, ao ser passada para CBL_CREATE_FILE
, ainda faça referência ao mesmo arquivo a que se referia ao ser passada para CBL_CHECK_FILE_EXIST
. Se um invasor criar filename
após a chamada para CBL_CHECK_FILE_EXIST
, a chamada para CBL_CREATE_FILE
falhará, levando o programa a acreditar que o arquivo está vazio, quando, na realidade, ele contém dados controlados pelo invasor.root
que executa certas operações de arquivo em nome de usuários sem privilégios e usa verificações de acesso para garantir que ele não use seus privilégios de root para executar operações que não deveriam estar disponíveis ao usuário atual. Ao enganar o programa e fazer com que ele execute uma operação que, de outro modo, não seria permitida, o invasor pode aumentar seus privilégios.parse()
e format()
em java.text.Format
contêm uma falha de design que pode fazer com que um usuário veja os dados de outro usuário.parse()
e format()
em java.text.Format
contêm uma condição de corrida que pode fazer com que um usuário veja os dados de outro usuário.
public class Common {
private static SimpleDateFormat dateFormat;
...
public String format(Date date) {
return dateFormat.format(date);
}
...
final OtherClass dateFormatAccess=new OtherClass();
...
public void function_running_in_thread1(){
System.out.println("Time in thread 1 should be 12/31/69 4:00 PM, found: "+ dateFormatAccess.format(new Date(0)));
}
public void function_running_in_thread2(){
System.out.println("Time in thread 2 should be around 12/29/09 6:26 AM, found: "+ dateFormatAccess.format(new Date(System.currentTimeMillis())));
}
}
format()
.