garbage in, garbage out耳熟能详,如果你写的开源代码被输入到了代码生成工具Copilot中,会不会影响它的生成性能呢?纽约大学的研究员最近发现,Copilot生成的代码有超过40%都含有高危漏洞,究其原因竟然是GitHub提供的源代码自带漏洞!
随着AI技术的不断进步,程序员们好像不止想取代传统行业的人,而且还在积极思考如何取代自己,AI研究员们对「代码自动生成」更情有独钟。
结对编程(Pair programming)是一种敏捷软件开发的方法,两个程序员在一个计算机上共同工作。一个人输入代码,而另一个人审查他输入的每一行代码。
输入代码的人称作驾驶员,审查代码的人称作观察员(或导航员),两个程序员经常互换角色。
审查代码的人有时候也扮演「小黄鸭」,作用是听着驾驶员耐心地向自己解释每一行程序的作用,不用说话就可以激发驾驶员的灵感,还有助于发现bug。
如果观察员是一个AI,想象有一个AI助手和你一起结对编程是一种什么感觉?
今年六月,OpenAI 就和 GitHub 联手发布了一个新工具 GitHub Copilot,一时风头无两,只要写下注释,后面的代码内容基本都能预测正确,尤其对于写utils之类的函数来说实在是太方便。
但后来GitHub Copilot又卷入各种伦理风波中,有人认为他这是背诵代码,也有人认为可能会让使用者无意中抄袭了其他程序员的劳动成果,最关键的是,GitHub Copilot收费,网友认为你既然用的开源代码训练的模型,怎么能收费呢?
除了上述问题不谈,Copilot的安全性又怎么样?能不能生产出让人民放心、让百姓安心的好代码?
对此,来自纽约大学的研究员们最近发表了一篇论文,系统地对Copilot进行实验,通过为Copilot设计要完成的场景,并通过分析生成的代码的安全弱点来深入了解这些问题。
论文地址:
https://arxiv.org/pdf/2108.09293v2.pdf
garbage in, garbage out?
代码的质量由许多因素决定,但代码生成(code generation)更强调功能的正确性,这点通过能否正常编译和单元测试来衡量质量,或者使用文本相似性度量来衡量与预期的代码之间的差距。
与生成代码的功能正确性度量不同,评估Copilot提供的代码的安全性是一个开放的问题,并没有特定的解决方法。
除了由人工进行手动评估外,还可以用其他工具和技术可以对软件进行安全分析,例如源代码分析工具、静态应用程序安全测试(Static Application Security Testing, SAST)工具,都能够发现代码的安全缺陷,并且可以用于识别特定类型的漏洞。
使用Copilot时,当用户向程序添加一行代码后,Copilot会连续扫描程序,并定期上传一些代码、光标的位置和代码的元数据,然后再根据这些特征生成一些候选代码选项供用户插入。
Copilot能够生成与程序功能相关的代码,例如注释、docstring、函数名等,Copilot还能够为每个候选代码的置信度进行评分。
了解如何使用Copilot后,需要定义问题:如果一段代码包含了CWE中展示的特点,那么这段代码就是有漏洞的(vulnerable)。
CWE(Common Weakness Enumeration,通用缺陷枚举)成立于2006年,是由美国国土安全部国家计算机安全部门资助的软件安全战略性项目,是常见的源代码漏洞词典库和通用标准。
使用Github CodeQL来分析静态代码。上图中的代码是使用Copilot的top scoring选项来构建一段代码程序,使用CodeQL的
python-security-and-quality.qls测试套件中检查153个安全属性,可以发现报告SQL查询生成方法有漏洞(第14-16行),可能允许用户插入恶意SQL代码,在CWE的术语中是CWE-89(SQL注入)。
随后研究人员通过引导Copilot生成2021 CWE Top 25 相关的漏洞进行实验。首先对每个CWE漏洞,写下多个相关的代码提示(CWE scenarios),然后把这些这些不完整的代码片段输入到Copilot中生成代码。
为了简化实验过程,主要对Python, C和Verilog这三种语言进行试验。CodeQL能够很完善地Python和C的代码检测,选择Verilog的原因是测试Copilot对于非明星语言的代码生成能力。
每个代码片段,Copilot都要生成25个补全代码,然后,将每个候选代码与原始程序片段组合成为完整的代码,如果某些选项存在重大语法问题,即无法编译/解析,则会丢弃4b中的某些候选代码。如果简单的编辑操作(例如添加或删除单个大括号)就能够可编译的输出结果,那就可以基于正则表达式的工具自动进行这些更改。
在5a步,使用CodeQL内置的查询对每个程序进行评估,对于一些需要额外代码上下文或无法形成CodeQL可检查属性的CWE,需要由人工手动执行5c。在这一步中,CodeQL被配置为只检查特定CWE,并且不评估正确性,只评估漏洞。
第6步中输出评估结果。
论文中对25个CWE漏洞都有详细的实验描述,感兴趣的小伙伴可以戳原文。
40.48%都是BUG
实验结果总的来说不太理想。
从安全的角度来看,Copilot生成的代码中有大量的漏洞,大概比例为40.48%。由于Copilot的训练数据来自GitHub上可用的开源代码的训练,所以一定程度上认为这个安全质量评价也同样适用于GitHub中的代码。
也就是说,当某些bug在开源存储库中经常出现时,这些bug也更容易被Copilot生成出来。话虽如此,但也不应该对GitHub上存储的开源存储库的安全质量轻易下结论。
开源软件的另一个需要考虑安全质量的方面是时间的影响。随着网络安全形势的发展,某些文章所说的最佳实践(best practice)可能会慢慢变成反面教材,过时实践可能会永久地存在于训练数据中,并导致生成的代码也是不可靠的。
一个明显的例子是密码散列的DOW CWE-522方案,不久前MD5被认为是安全的,SHA-256被认为是安全的,但现在的最佳实践仍然要么涉及多轮简单的散列函数,要么使用像bcrypt一样上了年纪的加密库(优雅,但也老了)。
未维护和遗留代码也使用不安全的散列方式,Copilot从这些代码中学习,所以也会对程序员继续建议使用这些散列方法。
最后研究人员还是赞扬了Copilot,这样的次时代AutoComplete工具将提高软件开发人员的生产率,但使用Copilot作为结对编程的副驾驶时,开发人员应该保持警惕。
在理想情况下,在训练和生成过程中,Copilot应该与安全工具相配合,将引入安全漏洞的风险降至最低。