Java: какую информацию в трассировке стека ошибок мы обычно не хотим показывать пользователям?

Я новичок в Java, и я не очень знаком с правилами форматирования, используемыми трассировкой стека ошибок, когда она генерируется и впоследствии отображается конечному пользователю моего веб-приложения.

Мой опыт работы с базой данных 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 [email protected]
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 всегда быть там.

Ответы на вопрос(7)

Как уже говорили другие, вы не должны сообщать трассировку стека пользователям. Несколько других предложили вам показатьgetMessage() текст. рекомендуюnot делая это. КакЯ уже говорил раньше:

  • The message was created when the exception was thrown. It therefore at best can provide only very low level information, which can be inappropriate for reporting to a user.
  • Philosophically, using the message seems to me against the whole point of exceptions, which is to separate the detection and initiation of error handling (the throw part) from completion of handling and reporting (the catch part). Using the message means the message must be good for reporting, which moves responsibility for reporting to the location that should be responsible for only detection and initiation. That is, I'd argue that the getMessage() part of the design of Throwable was a mistake.
  • The message is not localised. Despite its name, getLocalizedMessage() is not much good because you might not know what locale you want to use until you catch the exception (is the report to go to a system log read by your English system administrators, or is it to pop up in a window for the French user of the GUI?).
Решение Вопроса

Вы не должны показывать какую-либо эту гадость своим пользователям. Это бессмысленно для большинства из них и не поможет вам. Как вы подозреваете, он также раскрывает внутреннюю часть вашей реализации, которая может указывать на уязвимости, которые может использовать злонамеренный пользователь.

Вместо этого вы должны перехватывать исключения, регистрировать их и показывать пользователям более понятное сообщение об ошибке. Ты можешь использоватьgetMessage() извлечь часть сообщения об исключении. Если в исключении нет сообщения, отобразите что-то вроде "нет доступных сведений".

ОБНОВИТЬ:

У меня есть некоторые комментарии, основанные на обновлении вопроса. Во-первых, я бы полностью изолировал пользователя от любых внутренних элементов вашей системы, чтобы быть доброжелательным к пользователю и для безопасности. (Например, даже знание того, что вы используете пакет java.sql, может привести к уязвимости для умного хакера.) Поэтому не используйте сообщение об исключении, первую строку трассировки стека или что-либо подобное при отображении чего-либо пользователю ,

Во-вторых, вы должны сопоставлять все ошибки от уровня исключения (на котором они встречаются в вашем коде) до сообщений, которые находятся на правильном уровне абстракции для пользователя. Правильный способ сделать это будет зависеть от внутренней части вашей системы и от того, что пользователь, возможно, пытался сделать при возникновении исключения. Это может означать структурирование вашей системы в слои, так что каждый слой, который перехватывает исключение, переводит его в исключение на более высоком уровне абстракции. Исключение Java может переносить другие исключения (причину). Например:

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);
    }
}

Тогда это может быть использовано на более высоком уровне в классе User:

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);
    }
}

(Надеюсь, ясно, что приведенный выше код предназначен для иллюстрации идеи преобразования исключений в более высокие уровни абстракции, а не в качестве предложения для кода, который вы должны использовать в своей системе.)

Причина, по которой вы хотите обрабатывать подобные вещи (вместо того, чтобы каким-либо образом массировать сообщение и / или трассировку стека), заключается в том, что исключение (например, IOException с сообщением «разрешение отклонено») может означать для пользователя совершенно разные вещи (и к вашей системе) в разных контекстах.

The string I want to display to user is Error description here.

Ты можешь использоватьException.getMessage() для этой цели, хотя, как предложил Хуан Мендес, рассмотрите возможность реализации более «удобной для пользователя» системы. механизм сообщений об ошибках для отображения ошибок конечному пользователю.

Если вы не хотите, чтобы конечный пользователь видел имена ваших классов, методов и полей в трассировке стека, рассмотрите возможность использования обфускатора, напримерProguard, Мне нравится печатать обфусцированные стековые трассировки в файлах журналов, а затем использовать ReTrace, чтобы разблокировать их для целей отладки.

(1) Is there anything potentially sensitive that you wouldn't want users to see in the error stack? If so, what? For example, file paths, server name/IP, etc.

Я думаю, это может зависеть от исключения Выбор регистрации исключения или исключения - это компромисс между безопасностью приложения и способностью эффективно диагностировать проблему, я принимаю его на индивидуальной основе и оставляю комментарии по мере необходимости, чтобы объяснить мои причины для регистрации или отсутствия регистрации.

Имена пользователей и пароли, очевидно, являются конфиденциальной информацией, которую вы не хотите показывать пользователю. Также, как вы сказали, пути файловой системы, имена серверов и IP-адреса также должны быть скрыты.

Exception.getMessage() Метод вернет только сообщение о сгенерированном исключении, а не всю трассировку стека. Но похоже, что в приведенном вами примере 2-я и 3-я строки также являются частью сообщения об исключении, так что это вам не поможет.

BUT Это не очень хорошая практика дляever покажите своим пользователям следы стека. Они могут содержать не только конфиденциальную информацию, но и для пользователя, они примерно так же удобочитаемы, как клингон. Вместо этого вы должны регистрировать все необработанные исключения, а затем отображать более удобное для пользователя сообщение.

Вы не должны показывать конечным пользователям информацию, которую они не могут понять, включая всю трассировку стека во всей ее полноте. Ошибка, которую вы должны показать, когда вы поймаете подобное исключение, должна выглядеть примерно так на языке ваших конечных пользователей:

  • Our program has experienced temporary difficulties. Please call technical support line for assistance.

Конечные пользователи могут не заботиться о внутренней организации вашей программы, базах данных, стеках и так далее. Все, что они знают, это то, что, по их мнению, должно иметь работу, просто провалилось, поэтому они ищут помощи.

Трассировки стека предназначены для журналов ошибок: вы можете сохранить их для себя или отправить по электронной почте в службу технической поддержки, но не хотите показывать их конечным пользователям.

Не показывать сообщение об исключении / трассировку стека напрямую конечному пользователю. Вместо этого попробуйте использовать подход «Исключение - отображение сообщений».

Например:

  • SQLException - Sorry, a database error occurred. Please try again later
  • RuntimeException / Exception - Sorry an error occurred. Please try again later

На самом деле, вы можете сделать его как можно более универсальным. Возможно, вы могли бы использовать собственное отображение кода ошибки. Например,E0001 заSQLException, E0000 заException и так далее, и показать это конечному пользователю. Это будет полезно, когда они в конечном итоге обращаются в службу поддержки с кодом ошибки.

Вы должны показывать только трассировки стека, когда ваше приложение находится в режиме отладки. В рабочем режиме вы должны показать общее сообщение об ошибке (или реализоватьException.getUserFriendlyMessage()) и зарегистрируйте ошибку (укажите идентификатор журнала, если это возможно).

Ваш ответ на вопрос