2012-06-08 17 views
11

Soy nuevo en Java y no estoy familiarizado con las reglas de formato utilizadas por un seguimiento de la pila de errores cuando se lanza y posteriormente se muestra a un usuario final de mi aplicación web.Java: ¿qué información en el seguimiento de la pila de error normalmente no deseamos mostrar a los usuarios?

Mi experiencia con la base de datos Oracle es que la pila de errores contiene información interna, como nombres de esquema y procedimiento y número (s) de línea que, aunque son útiles para la depuración, me gustaría evitar que el usuario vea. He aquí un ejemplo:

java.sql.SQLException : ORA-20011: Error description here 
ORA-07894: at "NAME_OF_SCHEMA.PROCEDURE_NAME", line 121 
ORA-08932: at line 10 

La cadena Quiero mostrar al usuario es Error description here. Puedo extraer esta cadena utilizando expresiones regex porque sé que (1) esta cadena está siempre en la primera línea, así que puedo extraer la primera línea del seguimiento de la pila de errores, y (2) esta cadena siempre comienza con Error y termina con el final de la línea. [Nota para los usuarios de Oracle (no quiero engañarlo): lo anterior solo se aplica cuando se utiliza RAISE_APPLICATION_ERROR con una cadena de error que comienza con Error, de lo contrario, el texto Error no está allí].

Mis preguntas para Java son:

(1) ¿Hay algo potencialmente sensible que no quiera que los usuarios ven en la pila de errores? ¿Entonces qué? Por ejemplo, rutas de archivos, nombre de servidor/IP, etc.

(2) ¿Existen reglas de formato para el seguimiento de la pila de errores de Java en las que pueda confiar para extraer la información no confidencial? O, ¿cómo otros abordan esta preocupación?

ACTUALIZACIÓN 1:

Gracias por todas las respuestas hasta el momento, han sido muy útiles. Si bien muchas personas comentan el uso de una función como getUserFriendlyMessage() para asignar errores a mensajes de usuario útiles, me pregunto si alguien podría ampliar esta asignación. Es decir, para los errores comunes (SQL, E/S, etc.), qué identificador "confiable" podría usarse para buscar en esta pila de errores para identificar el tipo de error que ocurrió, y luego qué cadena de texto correspondiente recomendaría para mapear a este mensaje de error para mostrar al usuario? La respuesta de @ Adarshr a continuación es un buen comienzo. Por ejemplo,

Identified Expected If found in error stack, display this friendly msg to user 
------------------- ---------------------------------------------------------- 
SQLException   An error occurred accessing the database. Please contact support at [email protected] 
IOException   Connection error(?). Please check your internet connection. 

Supongamos errores de compilación relacionados no tienen que abordarse, sino que más bien se centran aquellos errores que los usuarios finales pueden experimentar durante el uso normal. Como referencia, aquí hay una lista de mensajes de error en tiempo de ejecución: http://mindprod.com/jgloss/runerrormessages.html#IOEXCEPTION

Como alternativa, ¿es posible usar simplemente la PRIMERA LÍNEA del trazado de la pila para mostrar al usuario? Este enlace es una especie de lo que estaba haciendo en mi pregunta original anterior:

http://www3.ntu.edu.sg/home/ehchua/programming/howto/ErrorMessages.html

Por ejemplo, si el identificador Exception se utiliza siempre, uno podría simplemente extraer el texto que se interponga entre Exception y el fin de la primera linea No sé si podemos confiar en que Exception siempre estará ahí.

+0

He actualizado mi respuesta en función de su actualización. –

+0

Consulte esta pregunta relacionada: http://stackoverflow.com/q/7361201/545127 – Raedwald

Respuesta

7

No debe mostrar nada de ese galimatías a sus usuarios. No tiene sentido para la mayoría de ellos y no te ayuda. Como sospecha, también expone aspectos internos de su implementación que pueden sugerir vulnerabilidades que un usuario malintencionado podría usar.

En su lugar, debe detectar excepciones, registrarlas y mostrar un mensaje de error más comprensible para sus usuarios.Puede usar getMessage() para extraer la parte del mensaje de una excepción. Si la excepción no tiene ningún mensaje, muestre algo así como "no hay detalles disponibles".

ACTUALIZACIÓN:

tengo algunos comentarios sobre la base de la actualización pregunta. En primer lugar, aislaría por completo al usuario de cualquiera de las partes internas de su sistema, tanto para ser amable con el usuario como para la seguridad. (Por ejemplo, incluso saber que está usando el paquete java.sql puede sugerir vulnerabilidades a un hacker inteligente). Por lo tanto, no use el mensaje de excepción, la primera línea del seguimiento de la pila, ni nada por el estilo cuando muestre algo al usuario .

En segundo lugar, debe correlacionar todos los errores del nivel de excepción (en el que tienen experiencia en el código) con los mensajes que tienen el nivel de abstracción correcto para el usuario. La forma correcta de hacerlo dependerá de las funciones internas de su sistema y de lo que el usuario podría haber intentado hacer cuando se produjo la excepción. Esto podría significar estructurar su sistema en capas de modo que cada capa que capte una excepción lo traduzca en una excepción en una capa superior de abstracción. Una excepción de Java puede ajustar otras excepciones (la causa). Por ejemplo:

public boolean copyFile(File source, File destination) throws CopyException { 
    try { 
     // lots of code 
     return true; 
    } catch (IOException e) { 
     throw new CopyException("File copy failed", e); 
    } 
} 

Entonces esto podría ser utilizado en un nivel superior en una clase de usuario:

public boolean shareFile(File source, User otherUser) throws ShareException { 
    if (otherUser.hasBlocked(this) { 
     throw new ShareException("You cannot share with that user."); 
    } 
    try { 
     return copyFile(source, otherUser.getSharedFileDestination(source)); 
    } catch (CopyException e) { 
     throw new ShareException("Sharing failed due to an internal error", e); 
    } 
} 

(espero que sea claro que el código anterior está destinado a ilustrar la idea de convertir excepciones a niveles más altos de abstracción, no como una sugerencia de código que debe usar en su sistema.)

La razón por la que desea manejar este tipo de cosas (en lugar de masajear el mensaje y/o el seguimiento de la pila) es que excepción (por ejemplo, una IOException con mensaje " permiso denegado ") puede significar cosas totalmente diferentes para el usuario (y su sistema) en diferentes contextos.

+0

Gracias por los detalles, Ted, realmente lo aprecio. – ggkmath

1

Solo debe mostrar los seguimientos de pila cuando su aplicación se encuentre en modo de depuración. En el modo de producción, debe mostrar un mensaje de error genérico (o implementar un Exception.getUserFriendlyMessage()) y registrar el error (proporcione una identificación de registro si es posible).

1

La cadena que quiero mostrar al usuario es Error description here.

Puede utilizar Exception.getMessage() para este propósito, aunque, como sugiere Juan Méndez, considerar la implementación de un mecanismo de mensaje de error más "amigable" para señalar errores para el usuario final.

Si no desea que el usuario final vea los nombres de sus clases, métodos y campos en stacktrace, considere usar un ofuscador como Proguard. Me gusta imprimir stacktraces ofuscado en archivos de registro, luego usar ReTrace para desenfiltrarlos para fines de depuración.

(1) ¿Hay algo potencialmente confidencial que no desee que los usuarios vean en la pila de errores? ¿Entonces qué? Por ejemplo, rutas de archivos, nombre de servidor/IP, etc.

Puede depender de la excepción que se arroje, creo. Elegir registrar la excepción o no es una compensación entre la seguridad de la aplicación y poder diagnosticar efectivamente el problema, lo tomo caso por caso y dejo comentarios según sea necesario para explicar mi razonamiento para iniciar sesión o no iniciar sesión.

+0

Prefiero tener un método 'getUserFriendlyMessage' para que nunca mostremos nada demasiado técnico –

+0

@JuanMendes estuvo de acuerdo, en realidad hago un tipo similar de cosas en mi código –

+0

@JuanMendes No sé si estoy de acuerdo con eso. Si se puede lanzar la misma excepción en una variedad de contextos diferentes, es posible que desee mostrar un mensaje de error diferente por contexto. – Michael

5

No muestre el mensaje de excepción/stacktrace directamente al usuario final. En su lugar, intente utilizar un enfoque de Exception - Message mapping.

Por ejemplo:

  • SQLException - Lo sentimos, un error de base de datos. Por favor, inténtelo de nuevo más tarde
  • RuntimeException/Exception - Disculpe un error. Por favor, inténtelo de nuevo más tarde

De hecho, puede hacerlo lo más genérico posible. Tal vez podría usar un mapeo de código de error personalizado. Por ejemplo, E0001 para SQLException, E0000 para Exception y así sucesivamente y mostrar esto al usuario final. Esto será útil cuando finalmente se pongan en contacto con el servicio al cliente con el código de error.

+0

Interesante. ¿Hay una lista de palabras clave que podría buscar de manera confiable en el seguimiento de la pila? Usted mencionó algunas más arriba (por ejemplo, SQLException, RuntimeException). Sería genial si pudiera expandir su respuesta para incluir una lista de palabras clave confiables que podrían aparecer y respuestas apropiadas. Me gusta lo que tienes hasta ahora. – ggkmath

+0

Realmente depende de su aplicación. Incluso podrían ser clases de excepción personalizadas como 'MyRuntimeException' o' NoSuchProductException'. – adarshr

3

No debe mostrar ninguna información a sus usuarios finales que no puedan comprender, que incluye todo el trazado de la pila en su totalidad. El error que debe mostrar cuando detecta una excepción como esta debe decir algo como esto, en el idioma de los usuarios finales:

  • Nuestro programa ha experimentado dificultades temporales. Por favor llame a la línea de soporte técnico para asistencia.

Los usuarios finales no se preocupan por la organización interna, las bases de datos, las pilas, etc. de su programa. Todo lo que saben es que algo que pensaban que debería funcionar simplemente falló, por lo que están buscando ayuda.

Los rastreos de pila son para registros de errores: puede guardarlos usted mismo o enviarlos por correo electrónico al servicio de asistencia técnica, pero no desea mostrarlos a los usuarios finales.

+2

Estoy de acuerdo en general, pero creo que en ciertas situaciones puede ser útil proporcionar un poco más de información. Por ejemplo, si obtiene un tiempo de espera del servidor, podría ser un problema con su conexión de red, y si les proporciona esa información, es posible que puedan solucionarlo por sí mismos y no tengan que abrir un ticket de soporte –

+1

@KevinK - Lo único que la mayoría de los usuarios necesitarían saber es si el problema es permanente ("no funcionó y no va a funcionar"), temporal ("no funcionó, inténtelo más tarde"), o corregible por el usuario ("inicia sesión para dejar un comentario"). Decir al usuario que era "un problema con la conexión de red" no tendría sentido o, lo que es peor, intimidaría a los usuarios no técnicos. El programa solo debe mostrar mensajes que sean apropiados para el nivel de experiencia del usuario objetivo. (Por supuesto, una aplicación para desarrolladores puede tener una sensación más tecnológica, pero la idea sigue siendo la misma). –

1

Los nombres de usuario y las contraseñas son obviamente información delicada que no le gustaría mostrar al usuario. Además, como dijiste, las rutas del sistema de archivos, los nombres de los servidores y las direcciones IP también deberían estar ocultas.

El método Exception.getMessage() devolverá solo el mensaje de la excepción lanzada y no todo el seguimiento de la pila. Pero parece que en el ejemplo que proporcionó, la segunda y la tercera líneas también forman parte del mensaje de excepción, por lo que eso no lo ayuda.

PERO no es una buena práctica nunca muestran sus usuarios trazas de la pila. No solo pueden contener información sensible, sino que para el usuario son tan legibles como Klingon. Debería estar registrando todas las excepciones no detectadas en su lugar, y luego mostrando un mensaje más fácil de usar para el usuario.

+0

Buen punto. Pero si hay palabras clave confiables en lo que Exception.getMessage() devuelve, podría buscarlas y reemplazar este mensaje con algo más apropiado. Vea mi ACTUALIZACIÓN 1 en la publicación original anterior. – ggkmath

1

Como han dicho otros, no debe informar el seguimiento de la pila a los usuarios. Varios otros le sugirieron que muestre el texto getMessage(). Recomiendo no haciendo eso. Como I've said before:

  • El mensaje se creó cuando se lanzó la excepción. Por lo tanto, en el mejor de los casos puede proporcionar información de muy bajo nivel, lo que puede ser inapropiado para informar a un usuario.
  • Filosóficamente, usar el mensaje me parece contra todo el punto de excepciones, que es separar la detección y el inicio de la gestión de errores (la parte throw) desde la finalización de la gestión y la creación de informes (la parte catch). Usar el mensaje significa que el mensaje debe ser bueno para informar, lo que mueve la responsabilidad de informar a la ubicación que solo debería ser responsable de la detección e iniciación. Es decir, yo diría que la parte getMessage() del diseño de Throwable fue un error.
  • El mensaje no está localizado. A pesar de su nombre, getLocalizedMessage() no es muy bueno porque es posible que no sepa qué configuración regional desea utilizar hasta que catch la excepción (es el informe para ir a un registro del sistema leído por los administradores del sistema inglés, o es para aparecer en un ventana para el usuario francés de la GUI?).
Cuestiones relacionadas