HttpSessionState
puede dañar la confiabilidad de la aplicación.HttpSessionState
, sus atributos y cualquier objeto al que hagan referencia en la memoria. Este modelo limita el estado de sesiones activas que puede alojar la memoria del sistema de un solo equipo. Para ampliar la capacidad más allá de estas limitaciones, los servidores se configuran con frecuencia para almacenar la información de estado de sesión, lo que permite ampliar la capacidad y efectuar la replicación entre varios equipos a fin de mejorar el rendimiento general. Para almacenar su estado de sesión, el servidor debe serializar el objeto HttpSessionState
, para lo que es necesario que todos los objetos almacenados sean serializables.[Serializable]
. Además, si el objeto requiere métodos de serialización personalizados, también debe implementar la interfaz ISerializable
.
public class DataGlob {
String GlobName;
String GlobValue;
public void AddToSession(HttpSessionState session) {
session["glob"] = this;
}
}
sleep()
mientras se mantiene un bloqueo puede provocar una pérdida de rendimiento y podría ocasionar un interbloqueo.sleep()
mientras se mantiene un bloqueo podría causar que todos los demás subprocesos esperen a que el recurso se libere, lo que podría dar lugar a un rendimiento degradado y un interbloqueo. sleep()
mientras mantiene un bloqueo.
ReentrantLock rl = new ReentrantLock();
...
rl.lock();
Thread.sleep(500);
...
rl.unlock();
if (fitz == null) {
synchronized (this) {
if (fitz == null) {
fitz = new Fitzer();
}
}
}
return fitz;
Fitzer()
, pero no desea pagar el coste de la sincronización cada vez que se llame al código. A este giro se le conoce como bloqueo de doble comprobación.Fitzer()
. Consulte la declaración "El bloqueo de doble comprobación está roto" para obtener más información [1].pthread_mutex_unlock()
antes de que otro subproceso empiece a ejecutarse. Si el subproceso que señala no puede desbloquear la exclusión mutua, la llamada pthread_cond_wait()
del segundo subproceso no volverá y el subproceso no se ejecutará. pthread_cond_signal()
, pero no puede desbloquear la exclusión mutua en la que espera el otro subproceso.
...
pthread_mutex_lock(&count_mutex);
// Signal waiting thread
pthread_cond_signal(&count_threshold_cv);
...
...
if (tmpnam_r(filename)){
FILE* tmp = fopen(filename,"wb+");
while((recv(sock,recvbuf,DATA_SIZE, 0) > 0)&&(amt!=0))
amt = fwrite(recvbuf,1,DATA_SIZE,tmp);
}
...
tmpnam()
, tempnam()
, mktemp()
y sus equivalentes de C++ precedidos de un _
(carácter de subrayado), así como de la función GetTempFileName()
de la API de Windows. Este grupo de funciones presenta una condición de carrera subyacente en relación con el nombre de archivo seleccionado. Aunque las funciones garantizan que el nombre de archivo es exclusivo en el momento de seleccionarlo, no hay ningún mecanismo que impida que otro proceso o un usuario malintencionado cree un archivo con el mismo nombre tras seleccionarlo, pero antes de que la aplicación intente abrirlo. Más allá del riesgo de conflicto legítimo provocado por otra llamada a la misma función, hay una alta probabilidad de que un usuario malintencionado pueda crear un conflicto malicioso debido a que los nombres de archivo generados por estas funciones no son lo suficientemente aleatorios para que sean difíciles de adivinar.open()
mediante los indicadores O_CREAT
y O_EXCL
, o a CreateFile()
mediante el atributo CREATE_NEW
, que presentará errores si el archivo ya existe y, por lo tanto, impide los tipos de ataques descritos anteriormente. Sin embargo, si un usuario malintencionado puede predecir con precisión una secuencia de nombres de archivo temporales, es posible que se impida que la aplicación abra el almacenamiento temporal necesario, lo que provocaría un ataque de denegación de servicio (DoS). Este tipo de ataque no sería difícil de implementar dado el reducido nivel de aleatoriedad empleado en la selección de los nombres de archivo generados por estas funciones.tmpfile()
y sus equivalentes de C++ precedidos de _
(carácter de subrayado), así como de una función de biblioteca C mkstemp()
con un comportamiento más eficaz.tmpfile()
crean un nombre de archivo exclusivo y abren el archivo del mismo modo que lo haría fopen()
si transfiriese los indicadores "wb+"
, es decir, como un archivo binario en modo de lectura/escritura. Si el archivo ya existe, tmpfile()
se truncará para establecer el tamaño cero, posiblemente en un intento por apaciguar las inquietudes de seguridad mencionadas anteriormente en cuanto a la condición de carrera que se produce entre la selección del nombre de archivo supuestamente exclusivo y la posterior apertura del archivo seleccionado. Sin embargo, este comportamiento no soluciona claramente los problemas de seguridad de la función. En primer lugar, un atacante puede crear previamente el archivo con permisos de acceso moderados que probablemente conservará el archivo abierto por tmpfile()
. Además, en los sistemas basados en Unix, si el usuario malintencionado crea previamente el archivo como vínculo a otro archivo importante, la aplicación puede utilizar los permisos posiblemente elevados para truncar ese archivo, dañándolo en nombre del usuario malintencionado. Por último, si tmpfile()
crea un nuevo archivo, los permisos de acceso aplicados al mismo variarán de un sistema operativo a otro, lo que puede dejar vulnerable la aplicación, incluso aunque el usuario malintencionado pueda predecir por adelantado el nombre de archivo que se va a usar.mkstemp()
supone un método razonablemente seguro para crear archivos temporales. Este intentará crear y abrir un archivo exclusivo basado en una plantilla de nombre de archivo proporcionada por el usuario, junto con una serie de caracteres generados aleatoriamente. Si no puede crear este archivo, presentará errores y devolverá -1
. En los sistemas modernos, el archivo se abre mediante el modo 0600
, lo que implica que el archivo se protegerá frente a su manipulación a menos que el usuario cambie de forma explícita los permisos de acceso. No obstante, mkstemp()
aún presenta problemas en relación con el uso de nombres de archivo predecibles y puede dejar vulnerable una aplicación frente a ataques de denegación de servicio si un usuario malintencionado provoca que mkstemp()
presente fallos mediante la predicción y la creación previa de los nombres de archivo que se van a utilizar.
...
try:
tmp_filename = os.tempnam()
tmp_file = open(tmp_filename, 'w')
data = s.recv(4096)
while True:
more = s.recv(4096)
tmp_file.write(more)
if not more:
break
except socket.timeout:
errMsg = "Connection timed-out while connecting"
self.logger.exception(errMsg)
raise Exception
...
open()
mediante los indicadores os.O_CREAT
y os.O_EXCL
, que presentará errores si el archivo ya existe y, por lo tanto, impedirá los tipos de ataques descritos anteriormente. Sin embargo, si un usuario malintencionado puede predecir con precisión una secuencia de nombres de archivo temporales, es posible que se impida que la aplicación abra el almacenamiento temporal necesario, lo que provocaría un ataque de denegación de servicio (DoS). Este tipo de ataque no sería difícil de implementar dado el reducido nivel de aleatoriedad empleado en la selección de los nombres de archivo generados por estas funciones.tmpfile()
.tmpfile()
crean un nombre de archivo exclusivo y abren el archivo del mismo modo que lo haría open()
si transfiriese los indicadores "wb+"
, es decir, como un archivo binario en modo de lectura/escritura. Si el archivo ya existe, tmpfile()
se truncará para establecer el tamaño cero, posiblemente en un intento por apaciguar las inquietudes de seguridad mencionadas anteriormente en cuanto a la condición de carrera que se produce entre la selección del nombre de archivo supuestamente exclusivo y la posterior apertura del archivo seleccionado. Sin embargo, este comportamiento no soluciona claramente los problemas de seguridad de la función. En primer lugar, un atacante puede crear previamente el archivo con permisos de acceso moderados que probablemente conservará el archivo abierto por tmpfile()
. Además, en los sistemas basados en Unix, si el usuario malintencionado crea previamente el archivo como vínculo a otro archivo importante, la aplicación puede utilizar los permisos posiblemente elevados para truncar ese archivo, dañándolo en nombre del usuario malintencionado. Por último, si tmpfile()
crea un nuevo archivo, los permisos de acceso aplicados al mismo variarán de un sistema operativo a otro, lo que puede dejar vulnerable la aplicación, incluso aunque el usuario malintencionado pueda predecir por adelantado el nombre de archivo que se va a usar.
...
HttpSession sesssion = request.getSession(true);
sesssion.setMaxInactiveInterval(-1);
...
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);
}
}
...
EXEC CICS
INGNORE CONDITION ERROR
END-EXEC.
...
doExchange()
.
try {
doExchange();
}
catch (RareException e) {
// this can never happen
}
RareException
, el programa continuaría ejecutándose como si no hubiera ocurrido nada inusual. El programa no registra ninguna evidencia que aluda a la situación especial, lo que podría frustrar cualquier intento posterior de explicar el comportamiento del programa.DoExchange()
.
try {
DoExchange();
}
catch (RareException e) {
// this can never happen
}
RareException
se fuese a iniciar en algún momento, el programa seguiría ejecutándose como si no hubiese ocurrido nada inusual. El programa no registrará ninguna prueba que indique la situación especial, evitando potencialmente cualquier intento posterior de explicar el comportamiento del programa.doExchange()
.
try {
doExchange();
}
catch (RareException e) {
// this can never happen
}
RareException
se fuese a iniciar en algún momento, el programa seguiría ejecutándose como si no hubiese ocurrido nada inusual. El programa no registrará ninguna prueba que indique la situación especial, evitando potencialmente cualquier intento posterior de explicar el comportamiento del programa.doExchange()
.
try {
doExchange();
}
catch (exception $e) {
// this can never happen
}
RareException
se fuese a iniciar en algún momento, el programa seguiría ejecutándose como si no hubiese ocurrido nada inusual. El programa no registrará ninguna prueba que indique la situación especial, evitando potencialmente cualquier intento posterior de explicar el comportamiento del programa.open()
.
try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except:
# This will never happen
pass
RareException
se fuese a iniciar en algún momento, el programa seguiría ejecutándose como si no hubiese ocurrido nada inusual. El programa no registrará ninguna prueba que indique la situación especial, evitando potencialmente cualquier intento posterior de explicar el comportamiento del programa.
PROCEDURE do_it_all
IS
BEGIN
BEGIN
INSERT INTO table1 VALUES(...);
COMMIT;
EXCEPTION
WHEN OTHERS THEN NULL;
END;
END do_it_all;
Exception
, se pueden ocultar excepciones que requieran un tratamiento especial o que no se deberían obtener en este punto del programa. Si se obtiene una excepción demasiado amplia, básicamente hace fracasar el propósito de las excepciones tipificadas de .NET, y puede resultar particularmente peligroso si el programa se desarrolla y comienza a iniciar nuevos tipos de excepciones. Los nuevos tipos de excepciones quedarán desatendidas.
try {
DoExchange();
}
catch (IOException e) {
logger.Error("DoExchange failed", e);
}
catch (FormatException e) {
logger.Error("DoExchange failed", e);
}
catch (TimeoutException e) {
logger.Error("DoExchange failed", e);
}
try {
DoExchange();
}
catch (Exception e) {
logger.Error("DoExchange failed", e);
}
DoExchange()
para iniciar un nuevo tipo de excepción que debería tratarse de forma diferente, el amplio bloque catch evitará que el compilador señale la situación. Además, ahora el bloque catch nuevo tratará también excepciones de los tipos ApplicationException
y NullReferenceException
, lo cual no es el propósito del programador.Exception
, se pueden ocultar excepciones que requieran un tratamiento especial o que no se deberían obtener en este punto del programa. Si se obtiene una excepción demasiado amplia, básicamente hace fracasar el propósito de las excepciones tipificadas de Java, y puede resultar particularmente peligroso si el programa se desarrolla y comienza a iniciar nuevos tipos de excepciones. Los nuevos tipos de excepciones quedarán desatendidas.
try {
doExchange();
}
catch (IOException e) {
logger.error("doExchange failed", e);
}
catch (InvocationTargetException e) {
logger.error("doExchange failed", e);
}
catch (SQLException e) {
logger.error("doExchange failed", e);
}
try {
doExchange();
}
catch (Exception e) {
logger.error("doExchange failed", e);
}
doExchange()
para iniciar un nuevo tipo de excepción que debería tratarse de forma diferente, el amplio bloque catch evitará que el compilador señale la situación. Es más, el nuevo bloque de filtrado ahora también administra las excepciones derivadas de RuntimeException
como ClassCastException
y NullPointerException
, que no es el propósito del programador.Exception
o Throwable
dificulta a los autores de llamada hacer un buen trabajo en cuanto al tratamiento y la recuperación de errores. El mecanismo de excepciones de Java se ha configurado para facilitar a los autores de llamada la anticipación de qué puede salir mal y escribir código para administrar cada circunstancia de excepción específica. Declarar que un método lance una forma genérica de excepción frustra este sistema.
public void doExchange()
throws IOException, InvocationTargetException,
SQLException {
...
}
public void doExchange()
throws Exception {
...
}
doExchange()
introduce un nuevo tipo de excepción que debería tratarse de forma diferente a las excepciones anteriores, no hay una forma fácil de exigir este requisito.NullPointerException
.NullPointerException
bajo tres circunstancias:NullPointerException
para señalar una condición de error.NullPointerException
.
try {
mysteryMethod();
}
catch (NullPointerException npe) {
}
NullReferenceException
.NullReferenceException
bajo tres circunstancias:NullReferenceException
para señalar una condición de error.NullReferenceException
.
try {
MysteryMethod();
}
catch (NullReferenceException npe) {
}
finally
provocará que las excepciones se pierdan.finally
provocará que todas las excepciones que se puedan lanzar en el bloque try se descarten.MagicException
lanzada por la segunda llamada para doMagic
con true
transferido a ella nunca se entregará al autor de llamada. La instrucción return dentro del bloque finally
provocará que la excepción se descarte.
public class MagicTrick {
public static class MagicException extends Exception { }
public static void main(String[] args) {
System.out.println("Watch as this magical code makes an " +
"exception disappear before your very eyes!");
System.out.println("First, the kind of exception handling " +
"you're used to:");
try {
doMagic(false);
} catch (MagicException e) {
// An exception will be caught here
e.printStackTrace();
}
System.out.println("Now, the magic:");
try {
doMagic(true);
} catch (MagicException e) {
// No exception caught here, the finally block ate it
e.printStackTrace();
}
System.out.println("tada!");
}
public static void doMagic(boolean returnFromFinally)
throws MagicException {
try {
throw new MagicException();
}
finally {
if (returnFromFinally) {
return;
}
}
}
}
finally
provocará que las excepciones se pierdan.finally
provocará que todas las excepciones que se puedan lanzar en el bloque try se descarten.exception
lanzada por la segunda llamada para doMagic
con True
transferido a ella nunca se entregará al autor de llamada. La instrucción RETURN dentro del bloque finally
provocará que la excepción se descarte."disappear before your very eyes!" . PHP_EOL;
echo "First, the kind of exception handling " .
"you're used to:" . PHP_EOL;
try {
doMagic(False);
} catch (exception $e) {
// An exception will be caught here
echo $e->getMessage();
}
echo "Now, the magic:" . PHP_EOL;
try {
doMagic(True);
} catch (exception $e) {
// No exception caught here, the finally block ate it
echo $e->getMessage();
}
echo "Tada!" . PHP_EOL;
function doMagic($returnFromFinally) {
try {
throw new Exception("Magic Exception" . PHP_EOL);
}
finally {
if ($returnFromFinally) {
return;
}
}
}
?>
ThreadDeath
no se vuelve a lanzar, el subproceso en cuestión podría no acabar.ThreadDeath
solo deben filtrarse si una aplicación tiene que limpiar después de finalizar de forma asíncrona. Si se filtra un error ThreadDeath
, es importante que se vuelva a lanzar para que el subproceso finalice realmente. El propósito de lanzar ThreadDeath
es detener un subproceso. Si ThreadDeath
es absorbido, puede impedir que un subproceso se detenga y dé lugar a un comportamiento inesperado, puesto que quien haya lanzado originalmente ThreadDeath
espera que el subproceso se detenga.ThreadDeath
, pero no lo vuelve a lanzar.
try
{
//some code
}
catch(ThreadDeath td)
{
//clean up code
}
throw
dentro de un bloque finally
rompe la progresión lógica de try-catch-finally
.finally
siempre se ejecutan después de su bloque try-catch
correspondiente y se utilizan frecuentemente para liberar recursos asignados, como controladores de archivos o cursores de base de datos. Lanzar una excepción en un bloque finally
puede derivar el código de limpieza crítico, puesto que la ejecución normal del programa se interrumpirá. stmt.close()
se deriva cuando se lanza la FileNotFoundException
.
public void processTransaction(Connection conn) throws FileNotFoundException
{
FileInputStream fis = null;
Statement stmt = null;
try
{
stmt = conn.createStatement();
fis = new FileInputStream("badFile.txt");
...
}
catch (FileNotFoundException fe)
{
log("File not found.");
}
catch (SQLException se)
{
//handle error
}
finally
{
if (fis == null)
{
throw new FileNotFoundException();
}
if (stmt != null)
{
try
{
stmt.close();
}
catch (SQLException e)
{
log(e);
}
}
}
}