La computación distribuida trata sobre el tiempo y el estado. Es decir, para que más de un componente se comunique, debe compartir el estado, y todo esto requiere tiempo.
La mayoría de programadores antropomorfizan su trabajo. Piensan en un único puesto de control que lleva a cabo todo el programa de igual forma que harían ellos si tuviesen que realizar la tarea ellos mismos. Sin embargo, los equipos modernos cambian entre tareas con gran rapidez y, en una CPU múltiple con varios núcleos, o en los sistemas distribuidos, dos eventos pueden llevarse a cabo a la vez exactamente. Estos defectos hacen que sea urgente que se unan posturas entre el modelo de los programadores sobre cómo un programa se ejecuta y lo que sucede en la realidad. Dichos defectos están relacionados con interacciones inesperadas entre los puestos, los procesos, el tiempo y la información. Estas interacciones se producen a través del estado compartido: semáforos, variables, el sistema de archivos y, básicamente, cualquier cosa que pueda guardar información.
HttpSession
puede dañar la confiabilidad de la aplicación.HttpSession
entre varios JVM. De este modo, si un JVM deja de estar disponible otro puede intervenir y ocupar su lugar sin deteriorar el flujo de la aplicación.Serializable
.
public class DataGlob {
String globName;
String globValue;
public void addToSession(HttpSession session) {
session.setAttribute("glob", this);
}
}
block.timestamp
o block.number
como un proxy de tiempo.block.timestamp
o block.number
suelen ser usados por los desarrolladores para activar eventos dependientes del tiempo; sin embargo, estos valores a menudo dan una sensación de tiempo que no es seguro usar.block.timestamp
no es fiable y, en el peor, los mineros maliciosos pueden alterar la marca de tiempo de sus bloques si ven una ventaja en hacerlo.block.number
, aunque es posible predecir el tiempo entre bloques (aproximadamente 14 segundos), los tiempos de los bloques no son constantes y pueden variar dependiendo de la actividad de la red. Esto hace que block.number
no sea fiable para los cálculos relacionados con el tiempo.block.number
para desbloquear fondos después de un cierto período de tiempo.
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
; en caso contrario, como false
. Desafortunadamente, como hay E/S que bloquea la devolución de llamada, esta se ejecutará de forma asíncrona y puede que se ejecute después de la comprobación if (authenticated)
, y como el valor predeterminado era true, irá en la instrucción if tanto si el usuario se ha autenticado realmente como si no.
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
. El programa realiza ciertas operaciones de archivo en nombre de usuarios no privilegiados, y usa comprobaciones de acceso para asegurar que este no usa sus privilegios origen para realizar operaciones que no deberían estar disponibles para el usuario actual. El programa utiliza la llamada al sistema access()
para comprobar si la persona que está ejecutando el programa tiene permiso para acceder al archivo especificado antes de que abra el archivo y realiza las operaciones necesarias.
if (!access(file,W_OK)) {
f = fopen(file,"w+");
operate(f);
...
}
else {
fprintf(stderr,"Unable to open file %s.\n",file);
}
access()
presenta el comportamiento previsto y devuelve 0
si el usuario que ejecuta el programa dispone de los permisos necesarios para escribir en el archivo y, de no ser así, devuelve -1. Sin embargo, debido a que tanto access()
como fopen()
realizan operaciones en los nombres de archivo en lugar de en los identificadores de archivo, no hay ninguna garantía de que la variable file
aún haga referencia al mismo archivo en el disco al transferirlo a fopen()
que cuando se transfirió a access()
. Si un usuario malintencionado sustituye file
tras la llamada a access()
por un vínculo simbólico a un archivo diferente, el programa utilizará sus privilegios raíz para realizar operaciones en el archivo, aunque se trate de un archivo que, de lo contrario, el usuario no podría modificar. Al engañar al programa para que realice una operación que, de lo contrario, no sería permisible, el usuario malintencionado ha obtenido privilegios elevados.root
. Si la aplicación es capaz de realizar cualquier operación que el usuario malintencionado no tendría permiso para realizar, se trata de un posible objetivo.
fd = creat(FILE, 0644); /* Create file */
if (fd == -1)
return;
if (chown(FILE, UID, -1) < 0) { /* Change file owner */
...
}
chown()
es el mismo que el archivo creado por la llamada a creat()
, pero esto no siempre es así. Como chown()
funciona en un nombre de archivo y no en un identificador de archivo, un atacante podría ser capaz de reemplazar el archivo con un vínculo a un archivo que no posee el atacante. La llamada a chown()
proporcionaría así al atacante la propiedad del archivo vinculado.CBL_CHECK_FILE_EXIST
para comprobar si el archivo existe antes de crear uno y lleva a cabo las operaciones necesarias.
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
se comporta tal y como se esperaba y devuelve un valor distinto de cero, que indica que el archivo no existe. Sin embargo, dado que tanto CBL_CHECK_FILE_EXIST
como CBL_CREATE_FILE
operan sobre los nombres de los archivos y no sobre los identificadores, no hay garantía de que la variable filename
todavía se refiera al mismo archivo en el disco cuando se pase a CBL_CREATE_FILE
que era cuando se pasó a CBL_CHECK_FILE_EXIST
. Si un atacante crea un filename
después de la llamada a CBL_CHECK_FILE_EXIST
, la llamada a CBL_CREATE_FILE
fallará, lo que llevará al programa a creer que el archivo está vacío, cuando de hecho este contiene datos controlados por el atacante.root
que realiza ciertas operaciones de archivo en nombre de usuarios no privilegiados, y usa comprobaciones de acceso para asegurar que este no usa sus privilegios origen para realizar operaciones que no deberían estar disponibles para el usuario actual. Engañando al programa para que realice una operación que no sería permisible de otro modo, el atacante puede ganar ciertos privilegios superiores.parse()
y format()
de java.text.Format
contienen un error de diseño que puede ocasionar que un usuario vea los datos de otro usuario.parse()
y format()
de java.text.Format
contienen una condición de carrera que puede ocasionar que un usuario vea los datos de otro usuario.
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()
.