低代码平台能天然防sql注入,因其所有查询均经querywrapper等抽象层参数化执行,用户输入仅作绑定参数而非字符串拼接;防护失效仅发生在开发者手动拼接sql、误用${}、或在高级sql字段中直写动态语句等破防场景。

JeecgBoot 这类低代码平台默认启用 SQL 注入防护,不是靠“加个开关”就能打开的,而是从框架层强制隔离用户输入与 SQL 执行逻辑——只要不手动绕过平台封装、不直写原生 SQL 拼接,基本不会中招。
为什么低代码平台能天然防 SQL 注入?
核心在于:所有数据查询操作都走平台预定义的 QueryWrapper、LambdaQueryWrapper 或类似抽象层,最终生成的 SQL 由框架内部用参数化方式执行,用户输入永远作为绑定参数传入,而非字符串拼接。
- 比如你在 JeecgBoot 的列表页配置“用户名模糊搜索”,后台实际执行的是
queryWrapper.like("username", username),不是"WHERE username LIKE '%" + username + "%'" - 平台自动生成的分页、排序、条件过滤等逻辑,全部基于表达式树或类型安全的构建器,不暴露 SQL 字符串拼接入口
- 即使你用代码区写 Java,只要调用的是
baseMapper.selectList(wrapper),底层仍是 MyBatis-Plus 的预编译语句
哪些操作会破坏内置防护?
防护失效几乎只发生在开发者主动“破防”的场景,典型包括:
- 在自定义 Java 方法里用
String.format()或+拼接 SQL,再传给mybatis.execute()或JdbcTemplate.query() - 使用
@Select("SELECT * FROM user WHERE name = '${name}'")这种 MyBatis 的非参数化注解(${}是字符串替换,#{}才是参数绑定) - 在 SQL 片段配置项(如 JeecgBoot 的“高级查询 SQL”字段)中手写带
CONCAT、UNION或变量插值的语句 - 调用存储过程时,把用户输入直接拼进
CALL proc(?)之外的语句体里
如何验证你写的扩展代码是否安全?
关键看 SQL 执行路径是否经过参数化封装。最简单的自查方式:
- 打开日志,搜索
Preparing: SELECT,确认后面跟的是带?或命名参数的语句,而不是展开后的完整 SQL - 在测试环境故意输入
admin' OR '1'='1,观察是否返回全表数据或报错;若返回空或正常单条记录,说明参数化生效 - 检查数据库连接池配置是否启用了
useServerPrepStmts=true&cachePrepStmts=true(MySQL 场景),避免 JDBC 自动退化为普通语句
真正容易被忽略的点是:平台防护只管“它生成的 SQL”,不管“你塞进去的 SQL”。低代码的安全性不来自平台多强大,而来自你有没有守住在它画的那条线之内。一旦跨出去写动态 SQL、反射调用、脚本引擎 eval,防护就形同虚设。











