夜雨聆风学习资料网

ARTICLE · 1094830

安全编码:从代码安全走向全生命周期的软件安全

安全编码:从代码安全走向全生命周期的软件安全

软件安全并不是在程序开发完成以后,通过一次漏洞扫描、一次渗透测试或者一次等级测评“检查”出来的。真正的安全应该从软件立项、需求分析和架构设计开始,贯穿编码、测试、发布、运行维护以及漏洞处置的全过程。安全编码(Secure Coding)因此不能简单理解为“程序员写代码时注意安全”,它实际上是将安全要求融入软件开发生命周期的一种工程实践,使安全成为软件功能、性能、可靠性和可维护性之外的一项基本质量要求。IBM将安全编码作为安全软件开发生命周期的重要组成部分,强调安全不应等到测试阶段才介入,而应该进入软件开发的各个阶段;Security Magazine所总结的安全软件开发实践同样强调,应当将安全要求、威胁评估、安全架构、开发、验证和运行维护结合起来,而不是把安全变成软件上线前的一次检查。

因此,安全编码首先不是从“写代码”开始,而应该从“提出安全要求”开始。在需求阶段,需要识别业务、数据、用户、接口以及外部依赖可能面临的安全风险,并形成明确的安全需求;进入架构设计阶段,则需要通过风险分析、威胁建模、安全设计模式等方法识别潜在的架构缺陷和业务逻辑风险。例如,一个系统需要实现患者信息查询功能,开发人员不能只考虑“查询功能能不能正常运行”,还需要考虑谁可以查询、能够查询哪些患者、可以查看哪些字段、是否允许批量查询、接口是否可能被越权调用、敏感数据是否需要脱敏、查询行为是否需要记录以及异常访问是否需要告警。如果这些问题直到编码完成以后才考虑,很多安全缺陷实际上已经固化在系统架构和业务逻辑之中。因此,真正的安全编码,第一步是把安全要求写进需求和设计。

在此基础上,组织还需要建立统一的安全编码规范,而不能主要依赖某个程序员个人的安全经验。不同开发人员掌握的编程语言、开发框架和编码习惯不同,如果没有统一的安全编码要求,同一种漏洞就可能在不同项目中反复出现。安全编码规范应当结合组织自身的技术栈和业务特点,对输入验证、输出编码、数据库访问、身份认证、访问控制、密码学、日志记录、错误处理、第三方组件以及安全测试等作出明确要求。例如,输入数据必须经过服务端验证,不能默认信任客户端数据;数据库操作应优先采用参数化查询;密码、密钥和令牌不能硬编码在源代码中;权限检查必须在服务端执行;关键安全事件应当记录;错误信息不能向外泄露内部系统信息;第三方组件应当纳入安全管理;安全代码审查应当成为软件发布前的重要环节。安全编码规范的意义,就是把“开发人员应该注意安全”转化为能够执行、能够检查、能够验证的具体要求。

安全编码中一个最基本的原则,就是不要默认信任任何输入。用户输入、URL参数、HTTP请求头、API参数、上传文件、第三方接口数据、消息队列数据,甚至内部系统传递过来的数据,都不应该仅仅因为来源于“内部网络”就自动被视为可信。输入验证需要根据具体业务对数据类型、格式、长度、范围、大小以及允许的字符和取值进行验证。但是,仅仅验证格式仍然不够,还需要根据数据最终使用的场景采取适当的处理方式。例如,Web应用需要针对不同输出上下文进行适当编码,数据库访问应采用参数化查询或者预编译语句,使用户输入的数据与SQL语句本身分离,从而降低SQL注入风险。安全编码不是简单增加一个判断条件,而是建立从输入验证、数据处理到安全输出的完整控制链。

密码学同样是安全编码中非常容易出现问题的领域。开发人员不应该自行设计加密算法,也不应该为了方便自行实现密码学核心功能,而应该使用经过验证、持续维护的密码学算法和安全库。尤其需要避免把密码、密钥和访问令牌直接写入源代码、配置文件或者版本控制系统。即使数据库中的敏感数据经过加密,如果密钥同时保存在程序代码中,一旦代码泄露,数据保护机制就可能失去意义。因此,密钥管理不能简单理解为“保存一个密钥”,而应该覆盖密钥的生成、存储、分发、使用、轮换、吊销和销毁等生命周期。对于传输中的敏感信息,也需要根据具体安全要求采取适当的保护措施,避免敏感信息在网络传输过程中被窃取或者篡改。

身份认证和访问授权也不能混为一谈。身份认证解决的是“你是谁”,而授权解决的是“你能够做什么”。一个用户成功登录系统,并不意味着他有权访问系统中的所有数据和功能。例如,普通员工即使成功登录业务系统,也不能因为知道某个URL中的患者ID,就直接访问其他患者的数据。因此,权限控制不能仅仅发生在用户登录的时候,而应当在访问受保护资源的过程中持续进行验证,并针对具体的用户、资源和操作进行授权判断。实际设计中,应贯彻最小权限和默认拒绝原则,只授予用户完成工作所必需的权限,并避免因为前端隐藏按钮、修改URL或者直接调用API而绕过服务端授权控制。

日志也属于安全编码的重要组成部分,但日志并不是“记录得越多越安全”。真正有价值的安全日志,应当能够说明谁、在什么时间、通过什么方式、针对什么对象执行了什么操作以及操作结果是什么。例如登录成功与失败、权限验证失败、关键数据访问、管理员操作、权限变更、配置变更以及重要安全异常等,都可能成为后续安全分析的重要依据。同时还必须防止日志本身成为信息泄露渠道,密码、密钥、访问令牌以及其他敏感信息不能因为方便调试而直接写入日志。日志还需要考虑访问控制、防篡改、安全传输和安全存储等问题。这样,日志才能真正成为安全运营的一部分,而不是简单的程序调试记录。

错误处理同样容易被忽视。很多程序正常运行时看起来没有问题,但发生异常以后,却直接将数据库连接信息、服务器路径、SQL语句、内部组件名称等技术细节返回给用户。这些信息对于开发人员可能有帮助,但对于攻击者同样具有价值。因此,安全错误处理应该形成“对外有限、对内详细”的原则,即用户只获得完成当前操作所需要的必要信息,而服务端则记录足够详细的诊断信息供开发和运维人员分析。这样既能够支持问题定位,又能够减少系统内部结构、数据库信息和敏感配置等内容向外暴露的风险。

代码完成以后,并不意味着安全开发已经完成。软件还需要经过自动化工具和人工验证。静态应用安全测试(SAST)可以从源代码层面发现潜在安全问题,动态应用安全测试(DAST)则可以从运行环境角度验证应用是否存在可利用的安全缺陷,交互式应用安全测试(IAST)能够结合运行时行为和代码上下文进行分析,软件成分分析(SCA)则重点关注第三方开源组件及其依赖关系。这些技术并不是相互替代,而是从不同角度发现问题。与此同时,人工代码审查仍然不可替代,因为自动化工具很难完全理解复杂的业务逻辑。例如,一个程序在语法和技术层面都没有明显漏洞,但如果业务授权逻辑存在缺陷,攻击者仍然可能通过正常功能实现越权操作。因此,自动化安全检测与人工安全代码审查应当形成互补。

现代软件越来越依赖开源框架、第三方库、SDK、容器镜像、插件和供应商开发组件,因此软件安全也不能只关注“我们自己写的代码”。一个组织即使没有在自己的代码中发现明显漏洞,所使用的第三方组件仍然可能存在已知漏洞或者供应链风险。因此,需要建立第三方软件和开源组件的识别、清单化、安全评估、版本管理、漏洞监测、更新修复和使用验证机制。特别是在CI/CD环境中,还需要关注代码来源、构建环境、依赖组件以及最终构建产物的完整性。由此可见,安全编码已经不再只是“开发人员与源代码之间的事情”,而是逐渐扩展到软件供应链、开发环境和构建体系。

软件上线以后,安全工作并没有结束,反而真正进入持续运营阶段。安全开发不能停留在“代码已经扫描过”或者“上线前已经测试过”。软件运行过程中仍然会发现新的漏洞,新的攻击技术也会不断出现,因此需要建立持续的漏洞和安全问题管理机制,对发现的问题进行分析、定级、分派、修复、验证和关闭。更重要的是,对于反复出现的同类漏洞,还应当开展根因分析。如果不同项目中持续出现SQL注入、越权或者敏感信息泄露问题,那么问题可能并不只是某个程序员的一行代码写错了,而可能反映出组织的安全编码规范、开发人员培训、代码审查、测试体系或者安全需求管理存在系统性缺陷。因此,漏洞管理的终点不应只是“把这个漏洞关闭”,而应该进一步降低同类问题再次发生的概率。

随着人工智能逐渐进入软件开发过程,安全编码也面临新的变化。AI可以帮助开发人员生成代码、解释代码、发现漏洞和提出修复建议,但AI生成代码并不天然安全。AI提高了代码生产效率,同时也可能提高不安全代码产生的速度,因此不能因为代码由AI生成,就降低代码审查和安全测试要求。未来的软件开发可能逐渐形成“人提出需求、AI辅助设计、AI生成代码、自动安全分析、人工安全审查、自动化测试、发布验证、运行监测、持续修复”的新模式。安全开发的重点也将从单纯要求“开发人员具备安全编码能力”,进一步发展为建立能够约束、验证和监督AI辅助开发全过程的安全工程体系。

从这个角度看,安全编码实际上可以形成一条完整的安全链条。从安全治理进入安全需求,从安全需求进入威胁建模和安全架构,再进入安全编码、自动化分析、安全代码审查和安全测试,经过安全发布以后进入持续运行监测、漏洞处置和根因分析,最终将运行过程中发现的问题重新反馈到需求、设计、开发和管理体系之中,形成持续改进的闭环。

因此,安全编码不能简单理解为“程序员写代码时多注意几个安全问题”,也不能把安全等同于上线前的一次漏洞扫描。Security Magazine所强调的安全软件开发实践,更侧重于建立贯穿开发和运营的整体安全体系;IBM则进一步将安全要求落实到安全设计、输入验证、输出编码、密码学、身份认证、访问控制、日志、错误处理、安全测试、代码审查以及第三方组件管理等具体实践中。二者结合起来,可以看到一个更加完整的逻辑:安全不是软件开发完成以后附加的一项检查工作,而应该成为软件从需求产生、架构设计、代码编写、测试验证到上线运行全过程的一项基本能力。

真正成熟的软件安全,也不是由安全部门替开发人员写代码,更不是通过一份扫描报告证明“软件安全了”,而是让业务、架构、开发、测试、安全、运维以及供应链相关人员共同承担相应责任,通过制度、规范、工具、流程和运营机制,把安全真正融入软件生命周期。只有这样,安全编码才能从“避免几个常见漏洞”的技术要求,真正发展成为组织持续构建和维护安全软件的工程能力。

往期回顾

等保、关保、数保、个保,网络安全与数据治理“四位一体”的体系化制度框架

网络安全等级保护制度统一框架辨析

我国网络安全治理体系的发展历程

为什么新时代不能再仅仅理解等级保护

构建新时代网络安全与数据安全“四位一体”治理框架

从等级保护到新时代“四位一体”综合治理小结

网络安全:感觉人人都在“开车”,却没人坐在驾驶位上

网络安全法律法规最新目录系列

未来真正的网络安全专家应该是什么样子?

网络安全等保系列


测评机构不应该背等级保护工作全部的锅

先弄清楚网络概念,再来谈网络安全等级保护吧!

测评机构能力要求新标准,取消了注册资本要求

“三同步”之正确理解成熟的“同步规划”

网络安全责任:从事后追责到事前防控,从部门负责到领导担责

网络安全等级保护:什么是等级保护制度?

网络运营者等级保护合规自查表

等级保护数据安全测评两张图重绘新鲜出炉

《网络安全法》第二十三条第(四)项合规分解

《网络安全法》第二十三条第(三)项合规分解

《网络安全法》第二十三条第(二)项合规分解

《网络安全法》第二十三条第(一)项合规分解

《网络安全法》第二十七条合规分解

信息安全技术 网络安全等级保护基本要求

数据分级直接影响等级保护等级

等级保护第一步:定级,现实很多单位未全做

等级保护第二步:备案,是责任单位“向”向公安机关备案

等级保护第三步:建设整改,建设整改是核心

等级保护第四步:测评,现实很多单位在违规

“两保一密三工作”统归等级保护一制度

网络安全等级保护自查清单(对照法条)

《网络安全法》修改与等级保护之间的一点浅析

正确理解等级保护工作的重要性

由“两高一弱”典型案例浅谈等级保护建设的现实困境

网络安全与等级保护制度

等级保护建设参考系列


网络安全管理制度:网络安全总体安全策略

网络安全管理制度:网络安全工作总体方针

关基保护系列


《网络安全法》第三十三条内容拆解

《网络安全法》第三十四条内容分解

《网络安全法》第三十五条内容分解

《网络安全法》第三十六条内容分解

《网络安全法》第三十七条内容分解

《网络安全法》第三十八条内容分解

《网络安全法》第四十条内容分解

《网络安全法》第四十一条内容分解

关键信息基础设施保护法律法规体系

关基安全合规之《网络安全法》法条解析

关键信息基础设施安全保护总体认识

李克强签署国务院令 公布《关键信息基础设施安全保护条例》

关键信息基础设施保护测评

关基测评与等保测评主要差异项对比

关基测评渗透测试基线

关基保护现行法律法规及相关材料目录一览表

《网络安全法》第六条关于关基的安排

新时代关键信息基础设施安全保护进入依法治理时代

依法履行双重责任:关基运营者不能止步于一般网络安全合规

数据安全系列


《数据安全法》第二十一条合规拆解

《数据安全法》第二十七条合规分解

《数据安全法》第二十九条合规分解

《数据安全法》第三十条合规分解

网络数据安全风险评估迎来里程碑进程

数据安全知识:什么是数据安全

结构化数据(Structured Data)与非结构化数据(Unstructured Data)

数据处理者合规自查清单

我国数据安全合规遵循性文件一览

在《医疗卫生机构数据安全和个人信息保护管理办法》下如何合规

数据安全等级测评

数据安全合规自查表(Checklist)基于风险评估

单位数据安全自查清单(依据《网络数据安全管理条例》)

医疗机构数据安全和个人信息保护自查简表(基于最新医疗机构管理办法)

网络数据委托方数据安全合规自查清单

数据安全合规自查表(Checklist)基于风险评估

数据安全技术 数据接口安全风险监测方法

数据安全技术 数据安全风险评估方法

信息安全技术 网络数据处理安全要求

数据安全技术 敏感个人信息处理安全要求

数据安全技术 个人信息保护合规审计要求

数据安全技术 数据分类分级规则

个人信息保护系列


个人信息保护政策法规问答(2026年4月)

我国个人信息保护合规遵循性文件一览

个人信息处理者合规工作自查清单

信息安全技术 个人信息安全规范

数据安全技术 个人信息保护合规审计要求

个人信息保护:个人信息去标识化指南思维导图

小型个人信息处理者个人信息保护合规审计自查表

相关学习资料