我是新来的Java和我没那么熟悉使用错误堆栈跟踪时,它抛出,然后显示给我的web应用程序的最终用户的格式规则。
我与Oracle数据库的经验是错误堆栈包含内部信息,如架构和过程名称和行号(一个或多个),其中,在调试时很有用,我想阻止用户看到。 下面是一个例子:
java.sql.SQLException : ORA-20011: Error description here
ORA-07894: at "NAME_OF_SCHEMA.PROCEDURE_NAME", line 121
ORA-08932: at line 10
我想向用户显示的字符串是Error description here
。 我可以使用正则表达式的表达式,因为我知道(1)这个字符串总是在第一行提取此字符串,所以可提取错误堆栈跟踪的第一行,和(2)此字符串总是开头Error
并结束与队伍的尽头。 [注意对Oracle用户(我不想误导大家):使用RAISE_APPLICATION_ERROR与开始与一个错误字符串时,上面只适用Error
,否则文字Error
是不存在的。
我对Java的问题是:
(1)有什么潜在的敏感,你会不会希望用户错误堆栈中看到了什么? 如果是这样,是什么? 例如,文件路径,服务器名/ IP等。
(2)是否有针对Java错误堆栈跟踪,我可以依靠提取非敏感信息的任何格式规则? 或者说,如何给别人解决这个问题?
更新1:
感谢所有的答复,到目前为止,他们已经非常有帮助。 虽然很多人发表评论我要使用的功能,如getUserFriendlyMessage()
来映射错误有用的用户信息,我不知道是否有人能在这个映射扩大。 也就是说,对于常见的错误(SQL,I / O等),什么是“可靠的”标识符可以用于搜索,以确定发生错误的类型此错误堆栈,然后你会推荐什么相应的文本字符串映射到这个错误信息展现给用户? @以下Adarshr的反应是一个良好的开端。 例如,
Identified Expected If found in error stack, display this friendly msg to user
------------------- ----------------------------------------------------------
SQLException An error occurred accessing the database. Please contact support at support@companyname.com.
IOException Connection error(?). Please check your internet connection.
假设编译相关的错误并不需要解决,而是注重那些最终在正常使用过程中用户可能会出现错误。 作为参考,这里的运行时错误消息的列表: http://mindprod.com/jgloss/runerrormessages.html#IOEXCEPTION
或者,是否有可能只使用堆栈跟踪的第一行显示用户? 此链接是有点什么,我在我的上面原来的问题得到的:
http://www3.ntu.edu.sg/home/ehchua/programming/howto/ErrorMessages.html
例如,如果标识符Exception
总是使用,一个可以简单地提取附带之间的文本Exception
和第一行的末尾。 我不知道我们是否能够依靠Exception
总是在那里。
You shouldn't show any of that gobbledygook to your users. It's meaningless to most of them and doesn't help you. As you suspect, it also exposes internals of your implementation that may suggest vulnerabilities that a malicious user might be able to use.
Instead, you should catch exceptions, log them, and show a more comprehensible error message to your users. You can use getMessage()
to extract the message part of an exception. If the exception has no message, then show something like "no details available".
UPDATE:
I have some comments based on the question update. First, I would totally insulate the user from any of the internals of your system, both to be kind to the user and for security. (For instance, even knowing that you are using the java.sql package may suggest vulnerabilities to a clever hacker.) So do not use the exception message, the first line of the stack trace, or anything like that when displaying anything to the user.
Second, you should be mapping all errors from the exception level (at which they are experienced in your code) to messages that are at the right level of abstraction for the user. The proper way to do that would depend on the internals of your system and what the user might have been trying to do when the exception was raised. This might mean structuring your system into layers such that each layer that catches an exception translates it into an exception at a higher layer of abstraction. A Java exception can wrap another exceptions (the cause). For instance:
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);
}
}
Then this could be used at a higher level in a User class:
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);
}
}
(I hope it's clear that the above code is meant to illustrate the idea of converting exceptions to higher levels of abstraction, not as a suggestion for code that you should use in your system.)
The reason that you want to handle things like this (instead of somehow massaging the message and/or stack trace) is that an exception (for instance an IOException with message "permission denied") may mean totally different things to the user (and to your system) in different contexts.
不要直接显示异常消息/堆栈跟踪到最终用户。 相反,尝试使用一个异常 - 消息映射方法。
例如:
-
SQLException
-对不起,发生了数据库错误。 请稍后再试 -
RuntimeException
/ Exception
-很抱歉,发生错误。 请稍后再试
事实上,你可以把它尽可能地通用。 也许你可以使用自定义错误代码映射。 例如, E0001
对SQLException
, E0000
为Exception
等,并显示此给最终用户。 这将是有益的,当他们最终与错误代码联系客服。
你不应该显示任何信息给最终用户,他们无法理解,包括所有在其全部的堆栈跟踪。 错误时,你捕获异常一样,应该读这样的事情,在你的最终用户的语言,你应该显示:
- 我们的计划已经经历了暂时的困难。 请致电寻求帮助技术支持线。
最终用户可以不关心你的程序的组织内部,数据库,堆栈,等等。 他们所知道的是,他们认为应该有工作有些事情失败了,所以他们正在寻找帮助。
堆栈跟踪是错误日志:您可以将它们保存为自己,或将它们通过电子邮件发送给技术支持,但你不希望向他们展示给最终用户。
你应该只显示堆栈跟踪,当您的应用程序处于调试模式。 在生产模式下,你应该表现出一般错误消息(或实施Exception.getUserFriendlyMessage()
并记录错误(如果提供尽可能日志ID)。
用户名和密码是你不希望展现给用户明显的敏感信息。 此外,像你说的,文件系统路径,服务器名称和IP地址也应该被隐藏。
该Exception.getMessage()
方法将返回抛出的异常的只是信息,而不是整个堆栈跟踪。 但它看起来像你给的例子,第二和第三线也异常信息的一部分,所以它不能帮助你。
但它不是很好的做法, 不断显示您的用户堆栈跟踪。 他们不仅可以包含敏感信息,但给用户,他们即将为可读的克林贡语。 你应该记录所有未捕获的异常,而不是,然后显示用户更友好的信息给用户。
我想向用户显示的字符串是Error description here
。
您可以使用Exception.getMessage()
用于此目的,但正如胡安·门德斯建议,考虑实施更多的“人性化”的错误消息显示错误信息给最终用户的机制。
如果你不希望最终用户看到你的类,方法,并在堆栈跟踪字段的名称,可以考虑使用像混淆器Proguard的 。 我想打印在日志文件中模糊的踪迹,然后用回扫到unobfuscate它们进行调试。
(1)有什么潜在的敏感,你会不会希望用户错误堆栈中看到了什么? 如果是这样,是什么? 例如,文件路径,服务器名/ IP等。
它可以取决于所抛出的异常,我想。 选择登录异常或不被应用的安全性之间的权衡,并能够有效地诊断问题,我把它放在一个案件逐案的基础上,并留下必要的注释来解释我的推理进行记录或不记录它。
正如其他人所说,你应该不报告堆栈跟踪用户。 其他几个人都建议您显示getMessage()
文本。 我不建议这样做。 正如我曾说过 :
- 当异常被抛出的创建消息。 因此它充其量只能提供非常低的水平的信息,这可能是不恰当的用户报告。
- 哲学上,使用消息在我看来,对整点的例外,这是分离的检测和错误处理的开始(的
throw
从处理完成和报告(部分) catch
的部分)。 使用该消息意味着消息必须是良好的报告,这对于该应只负责检测和启动位置报告移动责任。 也就是说,我要说的是, getMessage()
的设计的一部分Throwable
是一个错误。 - 没有本地化的消息。 尽管它的名字,
getLocalizedMessage()
是没有太大的好,因为你可能不知道你要使用,直到你在哪种语言环境catch
异常(是报告去用你的英语系统管理员读取系统日志,或者是弹出在GUI的法国用户的窗口?)。
文章来源: Java: what information in error stack trace do we typically not wish to show users?