文章概述
SDL建设是一件道阻且长的事,业内实践大都遵循从简到难、从右到左原则,按照“工具化-平台化-自动化”策略推进。万事开头难,《安全性非功能需求识别表》配合应用安全测试(AST)工具切入研发流程,是SDL推进的一个不错落脚点。
本需求表参考国标《GBT38674-2020信息安全技术 应用软件安全编程指南》、《OWASP安全编码规范快速参考指南》与业内实践创建,从数据清洗、数据加密与保护、访问控制、日志安全、资源使用安全、环境安全六个方面,梳理共200余项,供各位读者结合实际情况提取使用。
推进建议
长安不是一天建成的,就本表的落地推进而言,切忌生搬硬套!
推行之初建议各位读者结合所在公司当前代码安全测试能力,选取能够通过工具(如代码审计SAST、交互式应用程序安全测试IAST、Web漏扫DAST)进行验证的约20条关键需求项,作为初次实施的基线要求。从而降低测试人员验证门槛,减少首次实施时的研发流程卡点阻力,确保提出的红线需求均可闭环。
趁热打铁以问题为导向,通过统计指标(如通过率、高频漏洞、排名等)度量和激励研发质量,从而获取管理层与研发项目组认可,再结合自动化检测能力的开发进展,同步增加需求项,重视每条需求项的落地运行效果而不刻意追求数量。
顺势而为,需求表仅仅是SDL建设的切入点,一方面是通过“应试”模式,将具体的安全要求切入开发流程;另一方面也借此不断形成知识库沉淀,始终以问题为需求,逐步推动工具向平台的集成,自动化覆盖率的提升,到更进一步的安全组件库建立健全、STRIDE威胁模型分析等。
笔者所在公司同步开展了开源IAST自研与安全需求表编制,IAST发布前计划推出15条安全需求纳入流程,并结合Burpsuite使用手册试运行,后续逐步实现IAST自动化测试替代。文末也将给出“关键需求项+验证方法”供大家参考,也欢迎大家多留言讨论。
表格填写说明
一、本表创建时,应按照开发过程文档命名规范重命名。
二、项目经理根据项目情况,填写项目经理、产品负责人、研发负责人、测试负责人等项目信息,以及各需求项的研发实现情况(内容较多时可关联文档附件,若不涉及则填写“不涉及”),便于测试人员对照验证。
三、在项目迭代过程中,若需求项无变化,则在说明中填写“继承‘XXX-XXX’项目需求表,无变化”;若存在需求项变化,则在“研发实现说明”中对变化项进行说明,并单独测试。
数据清洗
输入验证
为应用程序提供一个集中的输入验证规则,输入验证前,将数据按照常用字符进行编码 |
验证所有来自客户端的数据,严格验证以下场景: ·HTTP请求数据,包括表单域、URL参数、cookie、HTTP头以及URL自身传入 ·重定向输入的数据 ·来自命令行、环境及配置文件的输入 |
针对业务后端严格限制业务数据类型与数据范围,接口对参数进行校验,只接受本接口应该处理的参数 |
检测输入数据类型、长度(验证允许输入的最小和最大长度)、输入值(最小和最大边界值检查) |
默认禁止危险字符(常见如:< > " ' % ( ) & + \ \' \")输入;若必须被作为输入,请确保执行了额外的安全控制,比如:输入转义、输出编码、特定的安全 API等 |
验证路径之前应该先将其标准化为实际路径,重点验证空字节 (%00); 验证换行符 (%0d, %0a, \r, \n); 验证路径替代字符“点-点-斜杠”(../或 ..\);如果支持 UTF-8 扩展字符集编码,验证替代字符: %c0%ae%c0%ae/ (使用规范化验证双编码或其他类型的编码) |
输入数据检查,避免SQL注入攻击: ·使用参数检查的方式在参数拼接进SQL语句前进行过滤或者校验,拦截带有SQL语句的参数传入应用程序 ·对SQL语句的语义进行完整性检查,确认语义没有发生变化 ·使用预编译处理的方式处理拼接了用户可控参数的SQL语句 |
输入数据转义,避免XSS攻击: ·数据添加到html元素属性或者内容中时,对数据进行HTML转义 ·数据添加到script脚本中时,对数据进行script转义 ·数据添加到style中时,对数据进行css转义 |
可选:尽可能采用白名单机制(即默认拒绝)对输入数据进行验证 |
输出净化
通过语义输出编码方式,对所有从服务端返回到客户端的数据进行编码。比如HTML编码、URL编码等,编码形式需根据具体的应用场景选择 |
针对操作系统命令和SQL、XML、LDAP查询,语义净化所有不可信数据的输出 |
请求返回数据不应包含请求之外的业务数据,特别是敏感数据;禁止传递目录或绝对文件路径给用户,建议使用预设路径列表中的匹配索引值 |
禁止在错误响应中泄露系统的详细信息,如会话标识符、帐号信息、路径、组件版本等;避免显示调试或堆栈跟踪信息 |
禁止将URL重定向到用户可控的不可信站点 |
禁止使用前端来过滤敏感信息 |
可选:建议使用通用的错误消息或使用定制的错误页面 |
数据加密与保护
敏感数据分类
根据《数据安全法》《个人信息保护法》制定公司级数据分级分类规范,明确敏感数据字段表 |
产品经理根据公司、项目要求定义的数据,请具体说明 |
敏感数据处理
临时产生的敏感数据(写入内存或文件),应具有及时清除和释放机制 |
禁止将敏感信息(包含加密秘钥等)硬编码在程序中 |
可选:为敏感操作使用多因子身份验证机制,如短信验证码等 |
敏感数据传输
敏感数据传输需使用非对称加密算法(前端公钥加密,后端私钥解密) |
使用TLS协议1.2及1.2以上版本,原则上开始禁用低版本的TLS协议 |
禁止在HTTP请求参数中包含敏感数据,以及包括要求身份鉴别的数据内容、与外部系统交换的数据内容等 |
只使用HTTP POST请求方式传输身份验证的凭据信息 |
敏感信息需要展示在web页面上时,应在后台进行敏感字段脱敏处理 |
可选:需要展实完整敏感信息时,第一次只能获取到模糊信息(后端模糊处理),二次鉴权(如再输入一次密码)和图形验证码才能获取到全部信息 |
敏感数据存储
敏感信息必须采用认可的单向加密或杂乱编码加密后存储(禁止使用私有或者弱加密算法,如DES,SHA1等;推荐使用AES: 128位,RSA: 2048位,DSA: 2048位) |
禁止(包括在客户端)明文存储敏感数据 |
禁止在系统日志中保存敏感信息 |
可选:其他信息是否加密存储由产品经理决定 |
免责声明
应通过《隐私协议》、《服务协议》、软件许可等告知并取得用户同意,内容包括收集和处理用户个人信息的目的、类型、方式、范围,以及存储期限、存储地点,取得用户单独同意,不得超出约定的目的、范围、处理方式处理用户个人信息 |
网站中需要跳转到其他网站时,需要一个中转页面,并且带有明显免责声明 |
访问控制
口令安全
密码复杂度要求:长度不少于8位,包含字母、数字及特殊字符。设置场景中应具有密码复杂度检查功能(建议在后台验证密码复杂度) |
若用户密码由系统分配,初始密码必须随机生成,禁止初始密码明显包含用户个人信息或者账号相关属性;用户首次登录系统,密码必须被强制修改 |
输入框中,应校验输入数据合法性 |
采用基于哈希算法和加入盐值(salt)方式安全存储口令信息 |
密码传输过程应进行加密(建议使用https),cookie中不允许出现用户账号和密码 |
密码输入框应默认隐藏输入密码,或设计为密码显示/隐藏切换功能 |
密码不能输出到日志和控制台 |
密码重置和修改操作,需要进行二次合法身份验证(如认证旧密码、注册手机号和邮箱等) |
密码重置链接只能发送到预先注册的邮件地址或预先绑定的手机号,链接应限制短暂的可访问有效期(如10分钟),重置成功后禁止重复使用 |
当密码重新设置时,应使用单独信道(如短信、邮件),通知用户是否是本人在操作,告知安全风险 |
可选:密码必须至少每90天修改一次 |
可选:用户不能使用过去曾经使用过的3个密码 |
可选:若用户密码由系统分配,初始密码在发出5天内未做修改,账号建议被锁定 |
可选:提供密码定期修改提醒机制 |
图形验证码
一次性使用且不少于4位字符 |
验证码有效期不超过10分钟 |
由字母和数字组成,随机产生,包括足够的噪音干扰信息 |
在发送验证码时,严禁将验证码返回到客户端 |
用户3次输入错误密码后,自动弹出验证码输入框进行验证操作 |
可选:建议使用滑块验证码、计算值等复杂验证方式 |
短信验证码
一次性使用且不少于4位字符 |
验证码有效期不超过10分钟 |
短信内容需要明确告知客户当前的操作,如“您正在进行XX操作,验证码为XXX”;需明确告知验证码有效期,如“验证码有效期为XXX秒” |
控制发送频率,每次获取时间间隔不少于60s,限制每天每个手机号码最大获取次数 |
在发送验证码时,严禁将验证码返回到客户端 |
可选:可添加图形验证码,保证需要人类交互才可以发送短信 |
身份鉴证
用户名唯一 |
注册和多次登陆失败时必须存在验证码 |
为所有身份鉴别使用一个集中实现的方法 |
所有的数据输入以后,才进行身份验证数据的验证,尤其是分步骤登录逻辑 |
严格控制并确保用户只能通过指定途径或通道访问系统,避免身份鉴别被绕过 |
需要进行检查的功能项,前后端都要进行校验(密码长度,复杂度等等),避免前端控制被绕过 |
所有需要验证码验证身份的操作,在执行操作时,必须参数和验证码一起验证,避免前端绕过 |
所有的身份验证控制应当安全的处理未成功的身份验证,比如给出错误模糊提示(使用“用户名或密码错误”,单独提示验证码错误),隐藏敏感信息 |
连续登录失败时锁定账号,次数不超过5次 |
尽量使用无法猜测的随机UUID,避免自增ID |
可选:当设计允许用户在多渠道终端同时登录时,建议应进行常用设备登录限制,并限制终端数量 |
可选:当需要验证数字证书时,应检查证书状态和证书持有者。只有有效未过期的、且证书的实际持有者与证书声明的持有者一致的证书才能被信任和使用 |
可选:登录成功后,显示上次成功登录的时间以及自上次成功登录以来失败的登录次数 |
可选:最小化角色授权,一个账号对应一个人而非一个组 |
可选:安全性要求高的系统应采用多因子身份鉴别方式 |
可选:支持账户强制失效,明确允许账户不使用的最长期限,并在账户停止时终止会话 |
权限管理
遵循最小权限原则,建立统一的访问控制策略,服务器端执行的访问控制规则和前端实施的访问控制规则必须匹配 |
在服务端对ID参数(如 id、pid、uid、orderID、venderID等)的每一次请求和操作,执行用户和对象的权限确认,避免典型越权漏洞 |
访问控制策略应限制只有授权的用户才能访问文件资源、受保护的URL、受保护的功能或服务、受保护的应用程序数据、与安全相关的配置信息 |
访问控制策略应限制只有授权的外部应用程序或接口才能访问受保护的本地程序或资源 |
对每个用户交互都要检测访问控制状态 |
针对不同级层用户对应的不同访问权限,并在产品手册中标明,提醒开发人员在开发过程中注意权限设置 |
对于分步骤完成的业务程序,对当前状态进行校验,避免乱序攻击漏洞;避免程序以错误的顺序运行,或者防止出现故障时,后续程序以不正常的流程运行 |
可选:当权限重新设置发生变更时,应记录好日志,并通知用户(短信、邮件)是否是本人在操作,告知可能存在的安全风险 |
会话管理
登录以后session必须更新,如使用request.changeSessionId() |
注销时请及时销毁session(非关闭)java中使用invalidate();注销功能应确保完全终止相关会话或连接 |
cookie大小需要被限制(建议最大为4k);会话cookie应设计有效期,超时后立即失效 |
cookie中需要设置secure 和 httponly 属性,详见Cookie安全要求 |
应用程序只识别有效的会话标识,会话标识应使用通过审核的算法,保证会话标识不会被破解 |
禁止在URL、错误信息或日志中暴露会话标识符,会话标识符应当只出现在Cookie头信息中,不要将会话标识符以 GET 参数进行传递 |
仅使用服务器授权后的会话标识对象,进行访问、修改等权限的决定,而不是依据对象属性,如uid |
使用“referer”头、csrf_token字段或自定义字段来校验用户请求的真实性 |
平衡风险和业务需求,设置一个尽量短的会话超时时间 |
需要周期性重新鉴别用户身份,以确保其权限未改变。如发生该别,应注销后强制重新执行身份鉴别 |
可选:每个页面明显位置均有用户“注销”按钮 |
可选:定期生成一个新的会话标识符并周期性地使上一个会话标识符失效 |
日志安全
日志功能要求
应对日志文件进行安全存储,如将日志文件独立保存于应用程序目录外,并使用严格的访问权限控制日志文件使用,禁止非授权用户访问 |
日志审计功能应禁止编辑或删除 |
对日志中的特殊元素进行过滤和验证,确保日志中的数据不会在查看界面或运行时,以代码的形式被执行 |
禁止在日志中保存敏感信息,包括不必要的系统详细信息、会话标识符或密码 |
可选:使用消息摘要算法以验证日志记录的完整性,防止攻击者篡改 |
可选:采取安全措施防止攻击者写任意的数据到日志中 |
日志记录范围
所有失败的输入验证、身份验证尝试、失败的访问控制 |
重要业务操作,如对数据库数据进行增、删、改 |
系统或服务的告警、故障、启动和终止 |
所有特权操作,包括查看日志、安全配置变更等 |
所有账号管理操作,如:账号的建立,更改,删除,账号的密码重置、锁定及激活,权限的修改 |
所有失败和成功的后端连接 |
加密模块的错误信息 |
可选:产品经理定义的重要功能 |
日志格式要求
用户ID |
日期、时间(至少精确到秒) |
终端身份和位置(如IP、MAC) |
事件名称 |
行为记录(事前及事后的数据转变) |
是否成功 |
可选:产品经理定义的格式 |
资源使用安全
文件管理
文件操作前应进行合法身份校验;采取白名单控制共享目录操作文件权限(读/写/可执行权限) |
在多用户系统中创建文件时指定合适的访问许可,以防止未授权的文件访问 |
禁止客户端自定义文件上传/下载路径(如:使用../../../../进行跳转) |
确保文件上传时不会覆盖重要内容,文件上传后按照命名规则重命名,防止不规则文件名的安全问题 |
只允许上传满足业务需要的相关文档类型,前后端均需对上传文件进行检查,检查内容应包括文件格式,文件内容,文件大小(文件大小由产品经理定义) |
通过检查文件头信息,验证上传文档是否是所要求的格式类型,详见“附_常用文件头16进制” |
禁止将文件保存在与应用程序相同的Web环境中 |
限制上传任意可能被 Web 服务器解析的文件 ,比如jsp、php等;如必须上传,需单独做好文件检测 |
禁止授予上传文件存储目录的可执行权限 |
可选:上传图片进行压缩,若上传文件太大(如媒体文件)应采用异步上传方式。 |
可选:上传文件以二进制形式下载,建议不提供直接访问 |
可选:建议采用专用的文档服务器保存文件,并单独配置文档服务器访问域名 |
可选:访问上传的文件之前,进行恶意代码扫描,并校验文件完整性 |
可选:建议在程序初始化时,建立临时文件夹,存放可能产生的临时文件。应只对该应用程序开放访问权限, |
数据库管理
禁止使用JDBC连接数据库与代码库 |
禁止使用管理员权限进行数据库连接,为每个应用使用单独的非特权权限,且配置有限的数据库连接数 |
禁止使用默认的角色、账户与默认数据库口令访问数据库 |
禁止敏感信息明文存放,采用加密或者哈希、混淆等方式对敏感信息进行脱敏存储 |
使用行级别的访问控制,限制每个请求使用户只能访问自己的数据 |
及时释放数据库资源,如连接、游标等 |
可选:建议使用自定义的错误信息对原始错误信息进行包装,可把异常信息存放在独立的数据库表中 |
可选:关闭所有不必要的数据库功能,如不必要的存储过程或服务、应用程序包,最小化需安装的功能和选项 |
接口管理
调用方来源IP控制,可通过防火墙、主机host deny、Nginx deny等进行实现 |
调用参数认证,需设计参数容错机制,避免出现参数可遍历敏感数据安全问题 |
调用方权限控制,包括调用频率、有效期等,对异常进行阻拦 |
可选:调用方身份认证,可通过key、secret、证书、数字签名等进行实现 |
内存管理
对缓冲区的读写操作进行边界检查,避免向指定的缓冲区外读取或写入数据 |
字符串操作时,检查字符串长度和终止符,保证字符串的存储具有足够的空间容纳字符数据和终止符 |
在循环中调用函数时,检查缓冲区空间大小,确保不存在超出分配空间的访问 |
及时释放内存,避免对同一块内存释放两次,已释放的内存再次分配前禁止写入 |
网络传输
不允许同一用户ID的并发登录 |
若会话在登录以前就建立,在成功登陆后,应关闭该会话并创建一个新会话 |
控制网络传输流量不超过被允许的值 |
对信道中传输的消息进行完整性验证 |
环境安全
组件使用安全
Nginx安全: ·关闭目录列举(默认关闭),确认是否真的关闭 ·关闭版本号显示 ·做好访问控制,利用Nginx自带访问限制,禁止公网IP访问内网主机。 ·启用HTTPS协议传输 ·防范Nginx 00%截断漏洞,避免文件上传漏洞 |
Tomcat安全: ·修改Tomcat的默认口令 ·升级到最新稳定版本,不建议跨版本升级 ·不要使用root用户启动Tomcat,使用普通用户启动 ·更改Tomcat的AJP管理端口,默认为8009、默认管理端口。默认8005 ·将Tomcat应用根目录配置为Tomcat安装目录以外的目录 ·隐藏Tomcat的版本信息 ·关闭war自动部署功能 |
Redis安全: ·为Redis设置访问密码,杜绝出现未授权访问。 ·强烈建议不要使用root账号运行Redis,以较低权限的账号运行Redis服务,并禁用该账号的登录权限。 ·设置访问控制 ·修改默认端口6379 |
其他通用安全要求: ·设置认证体系,不能出现空口令、弱口令等情况,防止未授权访问 ·最小化运行权限,默认禁止使用root运行,如需使用应特别说明 ·尽量通过配置文件、iptables、ACL控制访问源,默认禁止开放到公网,如需使用应特别说明 ·注意这些组件的相关漏洞,如果出现严重漏洞,需要进行补丁修复或版本升级,例如fastjson反序列化漏洞 ·注意配置文件的安全性,尽量不将明文写入配置文件中,可以采用隐藏密码或代理技术 |
可选:精简组件中不需要的功能、方法,避免产生安全隐患 |
可选:建议使用SSL Socket代替Socket来进行数据交互 |
开发环境安全
按需提供项目组成员权限,最小化owners数量 |
运行环境安全
禁止将源码上传到开源平台或社区,如Github、开源中国等 |
应用发布前,去除所有与调试和测试相关的代码、配置、文件、接口等 |
对重要的配置信息进行安全保护 |
删除用户可访问的源码中的注释 |
对APP应使用混淆、签名、加固等措施防止被逆向获取源码 |
可选:定期检查文件是否被篡改,如通过计算哈希值(HASH)进行对比 |
实践参考
以下为笔者当前在试运行阶段提供的实践参考,同步进行的还有对应培训和工具手册文档,还请各位读者在参考时注意。
功能场景 | 安全需求 | 测试方法 |
代码规范 | 业务后端需严格限制业务数据类型、数据范围、数据长度(验证允许输入的最小和最大长度)、输入值(最小和最大边界值检查) | 利用测试工具Burpsuite,构造业务限制范围之外的数据类型(如int改为string)、输入值(如将金钱属性的参数值改为负数)等,观察业务后端是否对构造的参数进行处理 |
使用通用的错误消息或使用定制的错误页面,严禁将错误提示信息返回到前端 | 输入不存在的页面(如)或提交畸形参数触发错误页面,查看返回信息中是否包含网站重要信息,如网站路径、操作系统、服务器版本、服务类型、OpenSSH版本、参数名等 | |
验证所有来自客户端的数据,避免存在SQL注入、XSS等常见WEB漏洞,严格验证以下场景: · HTTP请求数据,包括表单域、URL参数、Cookie、HTTP头以及URL自身传入 · 重定向输入的数据 · 来自命令行、环境及配置文件的输入。 · 使用参数检查的方式在参数拼接进SQL语句前进行过滤或者校验,拦截带有SQL语句的参数传入应用程序 · 对SQL语句的语义进行完整性检查,确认语义没有发生变化 · 使用预编译处理的方式处理拼接了用户可控参数的SQL语句 · 数据添加到html元素属性或者内容中时,对数据进行HTML转义 · 数据添加到script脚本中时,对数据进行script转义 · 数据添加到style中时,对数据进行css转义 | 利用IAST进行被动式扫描,发现业务中的SQL注入、XSS漏洞等 | |
禁止将业务代码上传至开源社区,禁止使用JDBC连接Gitlab与数据库造成敏感信息泄露 | 询问研发是否存在类似情况,并及时清理 | |
数据安全 | 符合公司对数据安全要求,参考《公司数据安全规范》,对业务中涉及的敏感数据进行保护 | 询问研发是否涉及业务敏感信息,查看数据库中存储的敏感业务数据是否加密 |
禁止在HTTP请求参数中包含敏感数据,以及包括要求身份鉴别的数据内容、与外部系统交换的数据内容等。敏感数据传输需使用非对称加密算法(前端公钥加密,后端私钥解密),禁止将身份验证信息通过GET方式进行传输 | 利用测试工具Burpsuite,查看所有的接口交互中,是否携带敏感信息,敏感信息是否加密 | |
如需在前端展示敏感信息时,应在后台进行敏感字段脱敏;如需展示完整敏感信息,应进行二次鉴权(如再输入一次密码、图形验证码等)才能获取到全部信息 | 查看涉及展示敏感信息的前端界面,是否进行了脱敏处理;完整展示前是否存在二次鉴权 | |
访问控制 | 为所有身份鉴别使用一个集中实现的方法,严格控制并确保用户只能通过指定途径或通道访问系统,避免身份鉴别被绕过 | 首先登陆高权限用户进行功能测试,记录高权限特有的访问路径、功能接口(如增删改查等); 然后登陆低权限用户账号,尝试调用高权限功能(复制粘贴高权限路径,尝试调用高权限接口),查看是否执行成功 |
在服务端对ID参数(如 id、pid、uid、orderID、venderID等)的每一次请求和操作,执行用户和对象的权限确认,避免典型越权漏洞 | 利用测试工具Burpsuite,修改参数中的自增id(如尝试加一、减一),判断业务后端是否正确处理 | |
cookie中需要设置secure 和 httponly 属性(如需通过HTTP进行三方对接,可忽略本项要求) | 利用IAST扫描器扫描 | |
使用“referer”头、csrf_token字段或自定义字段来校验用户请求的真实性,限制origin字段避免跨域漏洞。 | 利用IAST扫描器扫描 | |
日志记录 | 记录所有失败的输入验证、身份验证尝试、失败的访问控制、重要业务操作,如对数据库数据进行增、删、改。 | 执行失败输入、错误身份尝试、越权操作、数据库操作等,查看是否产生对应操作的日志记录 |
组件安全 | 禁止使用root账号运行第三方组件、服务等应用,如需使用第三方组件,应使用最新版本组件,避免存在披露过的漏洞 | 利用系统命令,查看服务运行用户是否为root,利用Sonar/IAST进行扫描 |
默认功能页面未授权访问,例如swagger接口文档授权访问,druid未授权访问、actuator未授权访问 | 利用IAST扫描器扫描 | |
禁止存在默认口令、弱口令 | 记录所有需登陆功能密码,判断是否存在弱口令 |