Web应用SQL异常时如何隐藏数据库详情?Struts框架适配方案问询
Got it, let's work through this problem where your Struts app is exposing sensitive database details (like schema names, constraint names) in SQL error messages during white hat security scans. Since you're already using ActionErrors and ActionError, we can build on that setup to mask those sensitive bits while keeping useful, user-friendly feedback.
Here's a step-by-step refined solution:
1. Create a Custom Exception Handler
First, build a centralized exception handler to intercept SQL-related exceptions, strip sensitive details, and map errors to generic, safe messages. This replaces the default Struts exception handling that dumps raw error info.
import org.apache.struts.action.ActionError; import org.apache.struts.action.ActionErrors; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ExceptionHandler; import org.apache.struts.config.ExceptionConfig; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.sql.SQLException; import java.util.regex.Matcher; import java.util.regex.Pattern; public class SensitiveSqlExceptionHandler extends ExceptionHandler { @Override public ActionForward execute(Exception ex, ExceptionConfig config, ActionMapping mapping, org.apache.struts.action.ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { String userFriendlyMessage = "操作失败,请稍后重试"; if (ex instanceof SQLException) { String rawError = ex.getMessage(); // Extract the core Oracle error code (e.g., ORA-00001) Pattern oraPattern = Pattern.compile("ORA-(\\d+):"); Matcher matcher = oraPattern.matcher(rawError); if (matcher.find()) { String errorCode = matcher.group(1); // Map specific error codes to user-friendly messages switch (errorCode) { case "00001": userFriendlyMessage = "数据重复,无法完成此操作"; break; case "01400": userFriendlyMessage = "必填字段不能为空,请检查输入"; break; case "02291": userFriendlyMessage = "关联数据不存在,请确认输入信息"; break; // Add more common error codes as needed default: userFriendlyMessage = "数据库操作异常,请联系管理员"; } } } // Add the sanitized message to ActionErrors ActionErrors errors = new ActionErrors(); errors.add(ActionErrors.GLOBAL_ERROR, new ActionError("error.global", userFriendlyMessage)); saveErrors(request, errors); // Redirect to the input page or error page (configure in struts-config) return mapping.getInputForward(); } }
2. Configure Struts to Use the Custom Handler
Update your struts-config.xml to register the custom handler for SQL exceptions, so all such errors go through our sanitization logic:
<struts-config> <!-- ... other configs ... --> <global-exceptions> <exception type="java.sql.SQLException" handler="com.yourpackage.SensitiveSqlExceptionHandler" path="/your-input-page.jsp"/> <!-- Add other DB-specific exceptions if needed (e.g., OracleSQLException) --> </global-exceptions> </struts-config>
3. Refine Action-Level Error Handling
If you're manually catching exceptions in your Actions (instead of relying on global handling), replace direct raw error message usage with a centralized message mapper:
First, create a utility class for consistent mapping:
import java.sql.SQLException; import java.util.regex.Matcher; import java.util.regex.Pattern; public class ErrorMessageMapper { public static String getFriendlySqlMessage(SQLException ex) { String rawError = ex.getMessage(); Pattern oraPattern = Pattern.compile("ORA-(\\d+):"); Matcher matcher = oraPattern.matcher(rawError); if (matcher.find()) { switch (matcher.group(1)) { case "00001": return "数据重复,无法完成操作"; case "01400": return "必填字段不能为空"; // Add more mappings default: return "数据库操作异常,请联系管理员"; } } return "操作失败,请稍后重试"; } }
Then use it in your Action:
public ActionForward update(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { try { // Your database update logic here } catch (SQLException ex) { String safeMessage = ErrorMessageMapper.getFriendlySqlMessage(ex); ActionErrors errors = new ActionErrors(); errors.add("updateError", new ActionError("error.update.failed", safeMessage)); saveErrors(request, errors); return mapping.getInputForward(); } }
4. Secure Logging (Critical for Security)
Even if users don't see raw errors, ensure your logs don't expose sensitive DB details. Log only the error code and stack trace (without raw message content):
import org.apache.log4j.Logger; public class YourAction { private static final Logger logger = Logger.getLogger(YourAction.class); public ActionForward update(...) throws Exception { try { // DB logic } catch (SQLException ex) { // Extract error code for logging String errorCode = extractOraErrorCode(ex); logger.error("Database operation failed with code: " + errorCode, ex); // Proceed to add sanitized message to ActionErrors } } private String extractOraErrorCode(SQLException ex) { Matcher matcher = Pattern.compile("ORA-(\\d+):").matcher(ex.getMessage()); return matcher.find() ? matcher.group(1) : "unknown"; } }
5. Test Thoroughly
Trigger various SQL exceptions (unique constraint violation, foreign key failure, null value violation) to verify:
- Frontend shows only sanitized, user-friendly messages
- No sensitive DB details (schema names, constraint names) are exposed anywhere
- All edge cases are covered by your error code mappings
内容的提问来源于stack exchange,提问作者user7491136

