当前位置: 首页 > 科技观察

如何产出规范、安全、优质的代码?

时间:2023-03-16 10:04:40 科技观察

对于一个软件开发团队来说,有哪些代码质量指标和扫描方式可以让团队产出规范、安全、优质的代码?让开发团队安全、透明、可靠地运行?本文总结了一些实践和工具,包括常用的代码质量扫描工具、代码质量指标、第三方依赖管理、安全运维等,主要适用于有Java/JavaScript技术栈的Web项目。希望对想要标准化自己项目的TechLeads有所帮助。帮助。代码扫描和常见的质量指标“起因常积于微不足道”,往往一些奇怪的bug都是由一些不规范的小问题引起的。德国飞机涡轮机的发明者帕布斯·海因提出了航空业飞行安全法。法律指出,在每一起严重事故的背后,必然有29起小事故、300起险情和1000起潜在事故。应用到软件开发中,如果项目中的代码杂乱无章,势必会在某个时候出很多问题。这里介绍一些常用的扫描工具和代码质量指标,可以在构建项目基础设施时引入,自动检查代码中潜在的问题,达到控制代码输出质量的目的。扫描工具(1)checkstyle:checkstyle是java项目中常用的一种扫描工具,用来检查源代码是否符合代码规范。检查项目主要包括:Javadoc注释、导入、长类和方法、空格、重复文件、复杂度等,默认使用sun的代码规则,也可以配置自定义代码规则。比如阿里就发布了相应的检验规则。(2)findbugs:利用BugPatterns的概念来查找代码中可能存在的bug。检查项目主要包括:不良编程习惯导致的问题、性能问题、安全问题、线程问题等。例如判断是否相等应使用equals而不是“=”运算符、流需要关闭、线程资源需要发布等等。findbugs的模式库对于提升编程体验也有很好的作用。您还可以导入和编写自己的BugPatterns细化检查机制。(3)simian:simian是一个检查重复和相似代码的工具。它的查重类似于纸质查重,会提示一定的相似度。可以单独运行,也可以作为checkstyle插件运行,比较小众。(4)pmd:pmd是一个跨语言的通用静态扫描工具,具有checkstyle和findbugs的部分功能,这里不再赘述。(5)ESlint/TSlint:前端界的checkstyle,TSlint是专门用来做TypeScript类型检查的,ESlint是作为代码风格检查工具使用的。但是现在ESlint也提供了TypeScript类型检查的功能,基本上ESlint可以把这两个功能结合起来。由于性能问题,TypeScript还采用了ESLint作为TSlint的替代检查工具。(6)SonarQube:SonarQube是一个开源的代码质量管理工具,主要用于管理源代码的质量。SonarQube不同于上述工具。SonarQube旨在提供一个平台,通过插件提供对各种语言的支持,也可以与checkstyle、pmd、simian等工具集成。SonarQube一般需要作为一个单独的服务部署,提供一个数据库,可以记录扫描结果等信息。(7)npmaudit:npmaudit是npm6之后版本自带的前端安全扫描工具,可以扫描npm依赖中潜在的漏洞威胁。这些引入的漏洞可能会威胁到用户开发的机器,也可能会被带入bundle文件并在线发布,造成安全问题。目前npmaudit会在npminstall完成后自动执行,需要注意安全威胁报告。(8)FortifySCA:FortifySCA(SourceCodeAnalyzer)是一款非常优秀的代码安全扫描工具,用于分析代码中潜在的安全问题。通过调用该语言的编译器或解释器,将代码(Java、C、C++等源代码)转换为中间媒体文件NST(NormalSyntaxTrcc),然后通过模式捕获漏洞库中存在的漏洞匹配。例如,不检查上传文件等XSS攻击。(9)OWASPDependency-Track:TheOpenWebApplicationSecurityProject(OWASP)是一个非盈利组织,提供许多安全标准、数据库、社区和培训。其中一个工具是OWASPDependency-Track,它检查第三方依赖包中的众所周知的漏洞,扫描结果会受到漏洞数据库更新的影响。(10)Archunit架构规范检查:前期检查是代码层面的,可以使用archunit进行代码架构检查,可以定义规则检查每个包中的实现是否符合规范。例如controller包下的类不能实现service接口,repository下的类必须实现Repository接口。通过archunit可以减少codereview的工作量,避免项目的结构被破坏。统计工具sloccount和sourcemointor这两个工具可以用来统计代码的数量,包括行数、文件数、注释等,除了扫描项目中的bug,配置代码统计工具可以有一个整体的了解的项目。其他的扫描工具还有很多,比如coverity、codemars、binscope、synk、appscan、retire.js等工具,就不一一列举了。这些工具的功能重叠。在实际工作中,我们可以根据上面推荐的关注点重点清理这些问题。使用所有这些扫描工具不仅会带来团队压力和维护成本,而且代码质量不会随着插件的引入而提高。除了提供这些扫描平台的拥有优质团队的大型工厂外,敏捷团队通常不会太大,团队最好继续专注于精简的扫描产品组合。Java后端:checkstyleJava代码风格卫士,Java项目至少应该配置一个默认的checkstyle规则。至少保持项目干净,没有无用的、重复的代码,以及超大的类和方法。建议每次提交代码前检查。findbugs常见的非标准代码检查,一些空指针,equals检查很有用,IDE插件也很好用。前端:eslint守护JavaScript代码风格,eslint搭配一个.editorconfig,可以轻松让编辑器保持和eslint一样的代码风格。npm审计项目中第三方包的威胁扫描。Npm无需额外安装。在npm6之后,它会自动运行。需要关注并修复上报的安全问题。安全性:fortify对代码进行漏洞扫描,其检测到的安全问题多为注入攻击、XSS等攻击,在开发过程中显然可以避免。可以配置为Jenkins插件,与单元测试在同一阶段运行。OWASP插件用于扫描第三方依赖漏洞,由于项目中的依赖不像源码那样经常变化,推荐使用Jekins插件,定时执行。为什么不使用SonarQube?SonarQube是一个非常好的代码质量开放平台。它需要单独配置和安装,并且需要额外的时间来维护。对于小团队来说,成本很高。如果你有专门的质量团队,你可以考虑维护一套。常用的代码质量指标是指编译警告的数量。大多数程序员基本上都忽略了警告,但是编译器发出的警告是一个不好的信号,这意味着软件可能可以运行,但是有不好的做法,而这种不确定性,会带来不确定的bug,最终让人迷惑。编译过程中的警告尽量消除,编译警告的值建议消除为0。函数代码平均行数,太大的函数会造成阅读困难,往往太大一个函数不够单一,一般把一个方法的代码行数控制在30-50行。平均文件代码行与平均功能代码行相同。太长的文件也难以维护。一般一个文件中有10个以上的方法,所以一个文件中的代码行数一般控制在300-500行。冗余代码,有时我们的代码中可能会存在未使用的方法、变量等代码,这让维护者感到困惑,通常需要清理。总文件重复率,重复文件的数量。除了写单元测试的情况,业务代码中不能有重复代码,推荐值为0。总代码重复度,代码重复度检查,受限于扫码工具的识别方式,需要一定的容忍度,推荐值为5%-10%平均函数圈复杂度,圈复杂度用来衡量一个模块的决策结构的复杂度。如果一个方法有大量嵌套的if语句,说明这个方法的实现质量低,程序复杂度高,不利于维护。推荐值小于5%。安全提示,如果配置了Fortify等安全扫描工具,应该清除安全威胁。代码缺陷,如果配置了缺陷扫描工具,如Findbus,需要清除。第三方依赖在标准化软件开发过程中,不可避免地会引入第三方或开源软件包作为库或框架。“第三方”实际上不是一个软件工程术语。今天软件界的理解是:第一方是自研软件,第二方是内部发布的软件,第三方是从社区或者外部商业渠道引入的软件包。对于个人开发者来说,为“搜索引擎”编程往往会在项目中引入来历不明的代码片段和包。对于企业来说,考虑的不仅仅是功能能否实现,还有成本和引入带来的问题,比如是否需要授权,开源协议是否合理,是否会带来安全威胁等。企业引入第三方依赖分为几种情况:作为开发工具引入,如gcc、Jenkins,基本不存在开源协议问题,但需要注意开发机的安全风险和CI。Jenkins存在漏洞,CI服务器被用作远程矿机。部署为服务(SaaS),一些开源协议会限制这种使用,第三方依赖的安全问题会威胁到服务器。大多数开源软件对这种通过软件包再分发的使用方式有更多的要求。比如GPL开源协议是有传染性的,要求使用GPL的项目也要开源。不建议复制源码导入项目,尽量通过包管理导入。第三方依赖的引入需要充分考虑,尽可能以最小的代价引入。在一个React前端项目中,一个陌生的工程师为了使用一个简单的手风琴效果,引入了一整套的bootstrap。它不仅打破了使用React的最佳实践,而且数倍地增加了输出包文件的大小,导致在加载第一个屏幕时出现性能问题。常见的商业友好型开源协议商业用户常用的开源协议其实只有六种左右,分别是LGPL、Mozilla、GPL、BSD、MIT、Apache,以及极其松散的TheUnlicense,但使用的开源软件并不多.GitHub提供了一份许可列表https://choosealicense.com/licenses/,我根据开源协议的松散度整理了一个列表方便查看:几乎所有的开源协议都有一个共同的注意事项:采纳开源的本协议的软件项目不提供任何责任转移和质量保证。也就是说,使用开源软件引起的法律问题与开源项目无关,用户需要承担因质量问题造成的一切后果。此外,除了导入的程序包外,字体、图片、特效音效、手册等媒体资源也属于广义的“软件”,需要考虑开源协议和使用场景。第三方依赖管理对于项目中任何第三方依赖的有效管理具有重要意义。通过扫描工具可以识别项目中的源码、jar包、二进制文件是否来自开源项目。任何第三方软件都需要申请入库管理(其他内部团队申请后可以直接使用),质量团队对申请的软件进行评估:是否有开源义务来完成引入的第三方依赖项是否有第三方开源软件中的CVE等漏洞还在维护吗?质量组根据以上条件决定申请的软件是否可以在项目中使用。允许采用的软件会定义首选级别,优先推荐给团队的首选软件,对项目的整体优化率有一定的要求。如果项目中的非约定目录中存在无法识别的二进制文件或代码片段,则需要上报。通过良好的依赖管理和标准化,可以减少不良第三方依赖的引入,使软件项目透明可信。一些商业公司提供这些完整的服务,比如f??ossil、blackduck、code-climate等。大运维安全的软件公司往往会有一堆流程和需求。虽然一线开发对堡垒机、防火墙和各种安全法规不耐烦,但这些安全措施也在保护着开发者。1.防火墙用于环境隔离。往往开发者都明白,防火墙是用来防止网络入侵、审计、入侵检测等功能的。此外,防火墙还可以用来隔离各种环境。一般而言,企业对生产环境的数据管控相对严格,不会将生产环境的权限交给团队中的所有开发人员,但网络连接可能会被忽略。曾经发生过一起网络事故。由于配置文件错误,将本应连接测试的数据库连接到生产环境,导致写入大量脏数据。如果环境由防火墙规则隔离,则不会出现此类问题。此外,还可以设计DMZ区,将面向用户侧的网关部署在DMZ区内,只向网关开放必要的端口,实现内外网的物理隔离。同时,整个系统的防火墙策略应该清楚地记录下来,否则在做重大基础设施更新时,很难把所有的防火墙策略都梳理清楚。2.凭证管理项目中会用到大量的凭证,例如数据库和第三方系统的密钥。使用纯文本不是一件好事。理想情况下,屏蔽项目中的所有密码信息,以避免CI和日志中的敏感信息泄露。有多种方法可以屏蔽项目中的密码信息:使用环境变量覆盖密码信息。使用Springboot的项目可以配置jasypt,使用jasypt对密码进行加密,将生成的加密字符串ENC(encryptedstring)配置到项目配置文件中。盐可以作为解密凭证添加到加密过程中。“盐”不需要存储在项目中,可以在项目部署时注入。如果使用Jenkins等CI/CD工具,可以使用构建平台提供的凭证管理工具。如果使用Springcloud,则可以使用springcloudvault组件来部署凭证管理服务。另外,建议不要使用任何个人凭证进行系统对接,应使用公共应用凭证。3.堡垒机一般来说,我们管理服务器,所有的运维操作都需要通过堡垒机进行。开放22等高危端口让开发者直接登录服务器是一种不安全的做法。堡垒机,通俗地说就是跳板机+监控。最初使用的跳板机配置了两块网卡连接开发环境和生产环境,没有监控功能。堡垒机在此基础上增加了统一运维管理的功能,往往需要进行两步验证(短信或Email),并对所有操作进行记录和监控。在需要团队参与运维工作的场景下,非常有必要部署一套堡垒服务器服务,使用LDAP连接团队成员ID,方便集中运维管理。4、定期扫描系统软件Linux系统经常有云厂商推送的安全补丁和风险提示,但是服务器上安装的软件,如JDK、nodejs等,需要自行检查是否存在安全问题。因此,有必要在系统上安装并定期运行CVEs检查并及时更新。有一个cvechecker可以帮助运维人员,写一个脚本定时运行cvechecker,检查系统中已知的软件是否存在CVEs漏洞,提醒开发者及时更新。写在后面刚开始工作的时候,喜欢动态灵活的编程语言,讨厌死板套路的编程语言。然而,过了很长时间才意识到“约束是程序员的朋友”。对一些安全知识的理解来源,大部分来源于修复SonarQube的经历。使用findbugs也让我对Java的基础有了更深入的了解。同样,在使用一些框架和平台的时候,往往也会有很多的限制。有时开发者很难意识到“限制”只是框架和平台的作者“保护”应用开发者的一种方式。一些开发者以破解框架和平台为乐,但这会带来潜在的隐患,在用户量增加后负面影响尤为明显。项目的标准化可以减少TechLead的程序运行事故和代码审查时间,并可能减少团队的加班时间。【本文为专栏作者“ThoughtWorks”原创稿件,微信公众号:Thinkworker,转载请联系原作者】点此查看该作者更多好文