导读:本期聚焦于花满楼创作的《如何修复政府类网站的SQL注入高危点?实施国密算法加密与访问控制加固》,敬请观看详情。政府类网站在安全测评中被通报最多的高危问题之一就是SQL注入漏洞,攻击者只需在查询参数中拼接恶意语句,就有机会读取甚至篡改后台数据库中的公民敏感信息,后果非常严重。本文围绕一次完整的整改实践,先分析SQL注入的产生原因和常见注入点定位方法,再演示如何用参数化查询、输入白名单校验等手段彻底修复漏洞,同时结合国密SM2、SM3、SM4算法对敏感字段做加密存储与传输保护,最后给出基于角色权限和最小权限原则的访问控制加固方案,帮助开发与运维人员完成符合等保要求的整体安全整改。

SQL注入长期稳居OWASP漏洞排行榜前列,在政府类网站的安全测评和等保整改中,几乎是每检必出的问题。这类漏洞的可怕之处在于,攻击者不需要任何特殊工具,只要在URL参数、搜索框或登录表单中构造恶意输入,就可能绕过身份验证、拖取整库数据,甚至通过数据库执行系统命令。由于政府网站往往承载大量公民个人信息,一旦被注入攻击得手,影响面和社会危害都远超普通站点。本文将结合实际整改经验,从漏洞定位、代码修复、国密加密改造到访问控制加固,给出一套可落地的完整方案。

如何修复政府类网站的SQL注入高危点?实施国密算法加密与访问控制加固

一、SQL注入漏洞的成因与注入点定位

SQL注入的根本原因是程序将用户输入直接拼接到SQL语句中,数据库无法区分哪些是开发者的原始意图、哪些是攻击者注入的指令。以一个典型的登录验证为例,很多老系统至今仍在使用字符串拼接的方式构造查询。

// 存在注入风险的写法
String sql = "SELECT * FROM sys_user WHERE username='" + username + "' AND password='" + password + "'";
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);

如果攻击者在用户名输入框中填入' or '1'='1' -- ,拼接后的SQL会变成恒真条件,直接绕过登录校验进入后台。更严重的情况是,攻击者利用union select逐字段探测列数,进而拖出用户表、配置表中的全部敏感数据。

定位注入点时,可以借助自动化扫描工具先做全站爬取和检测,但扫描结果只能作为参考,最终必须人工审计代码确认。重点排查以下几类位置:一是所有接收GET、POST参数后直接进入SQL语句的接口;二是排序字段、表名等无法参数化的动态拼接位置;二是模糊搜索中的like条件拼接;四是存储过程内部的动态SQL。建议在代码仓库中全局搜索StatementcreateQuery(execute(以及" + 这类拼接特征,逐条确认。

二、参数化查询与输入校验:彻底修复注入点

修复SQL注入的标准答案是参数化查询(也叫预编译语句)。其原理是先把SQL语句的骨架发送给数据库完成语法解析,参数值在后续阶段以独立数据形式传输,数据库不会把参数内容再当作SQL指令解析,无论攻击者输入什么都不可能改变语句结构。

// 修复后的参数化查询写法
String sql = "SELECT user_id, real_name, role FROM sys_user WHERE username = ? AND password_hash = ?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, username);
ps.setString(2, sm3Hash(password + salt));
ResultSet rs = ps.executeQuery();

有两类场景无法直接参数化,需要单独处理。第一类是排序字段和分页表名这类标识符,正确做法是建立白名单映射,例如前端传入sort=createtime时,后端在Map中查找对应的真实列名,查不到就直接拒绝请求,绝不把原始值拼进SQL。第二类是like模糊查询,要先把用户输入中的通配符转义,再将整个表达式作为参数传入,而不是在Java侧拼接百分号到SQL字符串里。

// 排序字段白名单校验
private static final Map<String, String> SORT_MAP = new HashMap<>();
static {
    SORT_MAP.put("createtime", "create_time");
    SORT_MAP.put("updatetime", "update_time");
    SORT_MAP.put("username", "username");
}
String orderColumn = SORT_MAP.get(sortParam);
if (orderColumn == null) {
    throw new IllegalArgumentException("非法的排序字段");
}
String sql = "SELECT * FROM sys_user ORDER BY " + orderColumn + " LIMIT ?, ?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, offset);
ps.setInt(2, pageSize);

除参数化之外,还应补充多层防御:在入口层对参数做类型和格式校验,例如身份证号只允许18位数字加末位校验字符,手机号必须匹配^1[3-9]\d{9}$;部署WAF拦截明显的注入特征;数据库层面删除多语句执行权限,并为应用分配专用低权限账号,即使被注入也难以执行load_fileinto outfile等危险操作。

三、引入国密算法:敏感数据的加密存储与传输

修复注入漏洞只解决了第一层问题,按照等保和密码应用安全性评估的要求,政府系统还需对敏感数据实施密码保护,防止拖库后数据明文泄露。国密算法体系中,SM3用于口令摘要,SM4用于数据加解密,SM2用于密钥交换和数字签名,三者配合可以覆盖存储和传输两个环节。

口令存储必须放弃MD5和SHA-1这类已被破解的算法,改用SM3加盐迭代摘要。盐值建议每个用户独立生成并随机存储,迭代次数不低于一万次,以对抗彩虹表和GPU暴力破解。下面以Java配合BouncyCastle为例给出实现。

// SM3加盐迭代口令摘要
public static String sm3HashWithSalt(String password, byte[] salt) throws Exception {
    MessageDigest digest = MessageDigest.getInstance("SM3", "BC");
    byte[] input = new byte[salt.length + password.getBytes().length];
    System.arraycopy(salt, 0, input, 0, salt.length);
    System.arraycopy(password.getBytes(), 0, input, salt.length, password.getBytes().length);
    byte[] result = digest.digest(input);
    for (int i = 0; i < 10000; i++) {
        result = digest.digest(result);
    }
    return Base64.getEncoder().encodeToString(result);
}

对于身份证号、手机号、家庭住址等字段,入库前用SM4加密,查询展示时解密。这里有个容易被忽视的坑:加密后的字段无法直接做等值查询和like检索。推荐的做法是增加一个SM3摘要列作为索引列用于精确查询,原文密文列只用于回显解密,这样既满足了加密要求,又不牺牲查询性能。密钥本身必须托管在专用密码机或密钥管理服务中,严禁硬编码在代码或配置文件里,密钥轮换周期建议不超过一年。

传输层面,将站点全站升级到HTTPS,并在国密改造场景中启用支持SM2套件的国密TLS证书,浏览器到服务器之间的所有报文都经过加密通道,防止中间人窃听和篡改。对于与上级政务平台的数据交换接口,报文体额外用SM4加密、SM2签名,实现应用层的双重保障。

四、访问控制加固:把权限关进笼子里

很多政府网站被攻破,并不是因为算法不够强,而是访问控制形同虚设。常见问题包括:登录后所有接口不校验角色,改一下URL中的ID就能越权查看他人材料;后台管理入口暴露在公网;会话标识不失效导致可以被重放。访问控制加固需要从认证、授权、会话三个层面同时入手。

认证层面,强制口令复杂度策略(长度不低于八位且包含大小写字母、数字、特殊字符中的三类),连续五次登录失败锁定账户十五分钟,关键系统叠加短信验证码或国密UKey做双因素认证。授权层面采用RBAC模型,将权限精确到按钮和接口级别,并在服务端统一拦截校验,绝不能依赖前端隐藏按钮来控制权限。所有涉及数据读取的接口都要校验资源归属,即当前用户是否对该条数据有操作权,防止水平越权。

// 越权校验示例:确认数据归属
Long currentUserId = SessionContext.getUserId();
ApplyRecord record = applyDao.findById(recordId);
if (record == null || !record.getUserId().equals(currentUserId)) {
    // 无权访问他人数据,返回统一的403响应并记录审计日志
    auditLog.warn("越权访问尝试 userId={} recordId={}", currentUserId, recordId);
    return Response.forbidden();
}

会话管理方面,登录成功后必须重新生成会话标识,防止会话固定攻击;会话空闲三十分钟自动过期;推出登录后服务端立即销毁会话而非仅清除前端Cookie。后台管理入口建议限制为政务外网或VPN访问,公网只保留面向公众的服务页面,从网络层面直接缩小攻击面。此外开启全量操作审计日志,记录谁在什么时间访问了什么数据,日志保留六个月以上,为事后溯源提供依据。

五、整改验证与持续运营

修复完成并不等于整改结束,必须通过复测验证效果。先用sqlmap等工具对原有注入点重新扫描,确认全部返回无害结果;再组织渗透测试,重点尝试越权访问、注入变体绕过和加密算法强度验证。整改报告要保留漏洞修复前后的对比证据,包括扫描报告、代码变更记录和复测截图,以备等保测评检查。

安全不是一次性工程,建议建立季度代码安全审计机制,在新上线功能中把参数化查询、输入校验、权限校验作为强制代码规范,通过代码评审和自动化SonarQube扫描双重把关。同时订阅CVE漏洞通告,及时升级框架和依赖组件,让SQL修复、国密加密、访问控制这套组合拳真正形成长期有效的防护体系。

SQL注入国密算法访问控制修改时间:2026-09-16 05:00:44

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。