{"record":{"id":"2b8c11e89411a789","repo":"jeecgboot/JeecgBoot","slug":"sql-table","errorCode":null,"errorMessage":"表名不合法，存在SQL注入风险!--->{table}","messagePattern":"表名不合法，存在SQL注入风险!--->(.+?)","errorType":"validation","errorClass":"JeecgSqlInjectionException","httpStatus":null,"severity":"critical","filePath":"jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/SqlInjectionUtil.java","lineNumber":405,"sourceCode":"\t\tint index = table.toLowerCase().indexOf(\" where \");\n\t\tif (index != -1) {\n\t\t\ttable = table.substring(0, index);\n\t\t\tlog.info(\"截掉where之后的新表名：\" + table);\n\t\t}\n\n\t\ttable = table.trim();\n\t\t/**\n\t\t * 检验表名是否合法\n\t\t *\n\t\t * 表名只能由字母、数字和下划线组成。\n\t\t * 表名必须以字母开头。\n\t\t * 表名长度通常有限制，例如最多为 64 个字符。\n\t\t */\n\t\tboolean isValidTableName = tableNamePattern.matcher(table).matches();\n\t\tif (!isValidTableName) {\n\t\t\tString errorMsg = \"表名不合法，存在SQL注入风险!--->\" + table;\n\t\t\tlog.error(errorMsg);\n\t\t\tthrow new JeecgSqlInjectionException(errorMsg);\n\t\t}\n\n\t\t//进一步验证是否存在SQL注入风险\n\t\tfilterContentMulti(table);\n\t\treturn table;\n\t}\n\n\n\t/**\n\t * 返回查询字段\n\t * <p>\n\t * sql注入过滤处理，遇到注入关键字抛异常\n\t *\n\t * @param field\n\t */\n\tstatic final Pattern fieldPattern = Pattern.compile(\"^[a-zA-Z0-9_]+$\");\n\tpublic static String getSqlInjectField(String field) {\n\t\tif(oConvertUtils.isEmpty(field)){","sourceCodeStart":387,"sourceCodeEnd":423,"githubUrl":"https://github.com/jeecgboot/JeecgBoot/blob/96fb33f5ec68516da0b0147da06b2eb0419e063a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/SqlInjectionUtil.java#L387-L423","documentation":"Thrown by SqlInjectionUtil.validateTableName when a caller passes a table name that fails the strict identifier regex (tableNamePattern). The validator enforces that table names contain only letters, digits and underscores, start with a letter, and stay within the 64-char limit. After the regex it also runs filterContentMulti() for deeper keyword injection checks. The goal is to block dynamic-table-name SQL concatenation attacks used by JeecgBoot's code generators and online form engines.","triggerScenarios":"Calling any API that lets the client choose a table name dynamically — code generator table import, online form binding, dynamic report datasource, jeecg-grid list queries with a 'tableName' param — where the supplied value contains characters outside [A-Za-z_][A-Za-z0-9_]{0,63}, e.g. 'sys_user;--', 'user` WHERE 1=1', or a 70-char name. Also triggered when schema-qualified names like 'dbo.users' are passed, because the dot fails the pattern.","commonSituations":"Passing a schema-prefixed table ('public.users'), passing a table with a hyphen or space, exceeding the 64-char MySQL identifier limit, a frontend form accidentally submitting the table caption instead of the real table name, or a malicious probe attempting stacked queries via the tableName parameter.","solutions":["Strip schema/db prefixes before calling validateTableName: pass only the bare table identifier, or extend the whitelist if schema-qualified names are legitimately required.","Pre-validate on the frontend/DTO with the same regex ^[A-Za-z][A-Za-z0-9_]{0,63}$ and reject early with a friendly message.","If you genuinely need dotted names, split on '.' and validate each segment separately instead of the whole string.","Confirm the caller is passing a real DB table name and not a UI label or column expression."],"exampleFix":"// before\nString table = \"public.sys_user\";\nSqlInjectionUtil.validateTableName(table); // throws\n\n// after\nString[] parts = table.split(\"\\\\.\");\nString bare = parts[parts.length - 1];\nSqlInjectionUtil.validateTableName(bare);","handlingStrategy":"validation","validationCode":"private static final Pattern TABLE = Pattern.compile(\"^[A-Za-z][A-Za-z0-9_]{0,63}$\");\npublic boolean isSafeTable(String table) {\n    if (table == null) return false;\n    String bare = table.contains(\".\") ? table.substring(table.lastIndexOf('.') + 1) : table;\n    return TABLE.matcher(bare.trim()).matches();\n}\n// call before SqlInjectionUtil.validateTableName(table)","typeGuard":"public static boolean isValidTableName(String t){\n    return t != null && t.matches(\"^[A-Za-z][A-Za-z0-9_]{0,63}$\");\n}","tryCatchPattern":"try {\n    SqlInjectionUtil.validateTableName(table);\n} catch (JeecgSqlInjectionException e) {\n    log.warn(\"rejected table name {}\", table);\n    return ResponseEntity.badRequest().body(\"Invalid table name\");\n}","preventionTips":["Always validate dynamic identifiers against a strict regex before they reach SQL.","Prefer schema-qualified names split and validated per segment.","Use a server-side whitelist of permitted tables/columns for user-driven queries."],"tags":["sql-injection","security","validation","jeecg-boot","database"],"backgroundTag":null,"analyzedSha":"96fb33f5ec68516da0b0147da06b2eb0419e063a","analyzedAt":"2026-08-14T00:04:16.786Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}