
VB安全编码规范
时间:2016-08-09 作者:zhankehua 评论:0 点击:2502 次
1. 概述
1.1. 目的
本文档为项目组所使用的VB,VB.NET编码规范。该规范源自于产品开发方法中的经验,并在不断完善。本规范的目的在于帮助公司开发人员提高开发效率,减少代码中出现的bug,并增强代码的安全性和可维护性。
另:采纳一个不熟悉的规范可能在初期会有一些不适应,但是这些不适应很快便会消失,它所带来的好处和优势很快便会显现,特别是在当您接手他人代码时。建议开发人员能够自觉遵守该规范。
1.2. 原则
在编写本规范时,遵循以下原则:
1) 易读性 – 语言描述和代码示例必须易读,且简单明确。它们必须能展示出重点所在。示例代码不可包含多余代码。它们必须带有相应文档说明。
2) 正确性 – 示例代码必须通过测试,确保其正确性,能够正确展现重点。示例代码要能够进行编译和运行。
3) 一致性 – 语言描述前后一致,示例代码应该按照一致的编程风格和设计来保证代码易读。
4) 时效性 – 代码示例应使用现行的编程实践,例如使用 Unicode,错误处理,以及可移植性。示例代码应当使用当前推荐的运行时库和API函数。
5) 合规性 – 代码示例必须符合法律,隐私和政策标准和规范。不允许展示入侵性或低质的编程实践,不允许永久改变机器状态。所有的安装和执行方法必须可以被撤销。
6) 安全性 - 示例代码应该展示如何使用安全的编程实践:例如最低权限原则,使用安全版本的运行时库函数,指出过时函数和替代函数等。
2. 术语
n 一定要:该规范或实践在任何情况下都应该遵守。除非您认为您的应用是例外,则可能不适用。
n 一定不要:不允许将该规范或实践应用到实际编程中。
n 应该:该规范和实践适用于大多数情况,如果符合您的实际情况,请遵循该规范。
n 不应该:不应该将该规范或实践,应用到您的实际编码当中,除非有合理的理由。
n 可以:该标准和规范您可以按需应用。
3. 通用编码规范
3.1. 简明性和一致性
√一定要确保代码的简明性,易读性和透明性。编程规范致力于确保代码是易懂和易维护的。没有什么胜于清晰、简洁、自描述的代码。
一定要确保一旦应用了本编程规范,要在所有代码中应用,以保持一致性。
3.2. 格式和风格
×一定不要使用制表符。不同的文字编辑器使用不同的空格来生成制表符,这就带来了格式混乱。所有代码都应该使用4个空格来表示缩进。可以配置Visual Studio 文字编辑器,以空格代替制表符。
√应该限制一行代码的最大长度。过长的代码降低了代码易读性。为了提高易读性,将代码长度可为78列。若78列太窄,可以为86或者90。
√一定要在您的代码编辑器中使用定宽字体,例如 Courier New。
3.3. 库的使用
×一定不要引用不必要的库,包括不必要的头文件,或引用不必要的程序集。注重细节能够减少项目生成时间,最小化出错几率,并给读者一个良好的印象。
3.4. 全局变量
√一定要尽量少用全局变量。为了正确的使用全局变量,一般是将它们作为参数传入函数。永远不要在函数或类内部直接引用全局变量,因为这会引起一个副作用:在调用者不知情的情况下改变了全局变量的状态。这对于静态变量同样适用。如果您需要修改全局变量,您应该将其作为一个输出参数,或返回其一份全局变量的拷贝。
3.5. 变量的声明和初始化
√一定要在最小的,包含该局部变量的作用域块内声明它。一般,如果语言允许,就仅在使用前声明它们,否则就在作用域块的顶端声明。
√一定要在声明变量时初始化它们。
√一定要在语言允许的情况下,将局部变量的声明和初始化或赋值置于同一行代码内。这减少了代码的垂直空间,确保了变量不会处在未初始化的状态。
Dim name As String = myObject.Name
Dim val As Integer = time.Hours
×一定不要在同一行中声明多个变量。推荐每行只包含一句声明,这样有利于添加注释,也减少歧义。例如:
Good:
Dim username As String
Dim password As String
Bad:
Dim username, password As String
3.6. 函数的声明和调用
√函数或方法的名称,返回值,参数列表可以有多种形式。原则上应该都将这些置于同一行代码内。如果带有过多参数不能置于一行代码,可以进行换行:多个参数一行或者一个参数一行。将返回值置于函数或方法名称的同一行。例如:
单行格式:
hr = DoSomeFunctionCall(param1, param2, param3)
多行格式:
hr = DoSomeFunctionCall(param1, param2,param3, _
param4, param5)
√将参数列表置于多行代码时,每一个参数应该整齐排列于前一个参数的下方。第一个类型/参数对置于新行行首,并缩进一个制表符宽度。函数或方法调用时的参数列表同样需按照这一格式。
hr = DoSomeFunctionCall(
hwnd,
param1,
param2,
param3,
param4,
param5)
√一定要将参数排序,并首先将输入参数分组,再将输出参数放置最后。在参数组内,按照能够指导编码人员输入正确值的原则来将参数排序。例如,如果一个函数带有2个参数, “left” 和 “right”,将 “left” 置于 “right” 之前,则它们的放置顺序符合其参数名。当设计一系列具有相同参数的函数时,在各函数内使用一致的顺序。比如,如果一个函数带有一个输入类型为句柄的参数作为第一参数,那么所有相关函数都应该将该输入句柄作为第一参数。
√一定要为每个参数指定数据类型。
√应该根据情况传递ByVal或ByRef。给每个参数冠以ByVal或ByRef所需要的规则是非常重要的
√一定要对数进行检验,决不要假设你得数据没有问题。程序员常犯的一个错误是在编写过程时假设数据没有问题。在初始编程阶段,当编写调用过程时,这样的假设并无大碍。这时你完全能够知道什么是参数的许可值,并按要求提供这些值。但如果你不对参数的数据进行检验,那么下列情况就会给你带来很大麻烦:另外某个人创建了一个调用过程,但此人不知道允许的值;你在晚些时候添加了新的调用过程,并错误的传递了坏数据。
√可以在参数只接受较小的一组值时,用枚举值。使用枚举值,可降低编码时出现数据输入错误的可能性。只要有可能,就可考虑使用枚举值。
3.7. 代码语句
×一定不要在同一行内放置多个代码语句。这会使得单步调试变得更为困难。
Good:
If (IsAdministrator()) Then
Console.WriteLine("YES")
End If
Bad:
If(IsAdministrator())Then Console.WriteLine("YES")
3.8. 枚举
√一定要将代表某些值集合的强类型参数,属性和返回值声明为枚举类型。
√一定要在合适的情况下尽量使用枚举类型,而不是静态常量。枚举类型是一个具有一个静态常量集合的结构体。
Good:
Public Enum Color
Red
Green
Blue
End Enum
Bad:
Public Class Color
Public Const Red As Integer = 0
Public Const Green As Integer = 1
Public Const Blue As Integer = 2
End Class
×一定不要使用公开集合作为枚举(例如操作系统版本,您亲朋的姓名)。
√一定要为简单枚举提供一个0值枚举量,可以考虑将之命名为“None”。如果这个名称对于特定的枚举并不合适,可以自行定义为更准确的名称。
Public Enum Compression
None = 0
GZip
Deflate
End Enum
×一定不要在.NET中使用 Enum.IsDefined 来检查枚举范围。Enum.IsDefined有2个问题。首先,它加载反射和大量类型元数据,代价极其昂贵。第二,它存在版本的问题。
Good:
If (c > Color.Black Or c < Color.White) Then
Throw New ArgumentOutOfRangeException(...);
End If
Bad:
If Not [Enum].IsDefined(GetType(Color), c) Then
Throw New ArgumentOutOfRangeException(...)
End If
3.8.1. 标志枚举
标志枚举用于对枚举值进行位运算的支持。标志枚举通常用于表示选项。
√一定要将 System.FlagsAttribute 应用于标志枚举。一定不要将此属性用于简单枚举。
√一定要利用2进制强大的能力,因为它可以自由的进行位异或运算。例如:
<Flags()>
Public Enum AttributeTargets
Assembly = &H1
Struct = &H4
...
End Enum
√应该提供一些特殊的枚举值,以便进行常见的标志枚举的组合运算。位运算属于高级任务,所以在简单任务中无需使用它们。FileAccess.ReadWrite 便是标志枚举特殊值的一个示例。然而,如果一个标志枚举中的某些值组合起来是非法的,您就不应该创建这样的标志枚举。
<Flags()> _
Public Enum FileAccess
Read = &H1
Write = &H4
ReadWrite = Read Or Write
End Enum
×不应该在标志枚举中使用0值,除非它代表“所有标志被清除了”,并被恰当的命名为类似“None”的名字。如下示例展示了一常见的检查某一标志是否被设置了的实现(查看如下 if-语句)。该检查运行结果正确,但是有一处例外,便是对于0值的检查,它的布尔表达式结果恒为true。
Bad:
<Flags()>
Public Enum FomeFlag
ValueA = &H0 '这样可能使用户迷惑
ValueB = &H1
ValueC = &H2
ValueBandC = ValueB And ValueC
End Enum
Good:
<Flags()>
Public Enum BorderStyle
Fixed3D = &H1
FixedSingle = &H2
None = &H0
End Enum
Function MyTest()
If foo.BorderStyoe = BorderStyle.None Then
...
End If
End Function
3.9. 空格
3.9.1. 空行
√应该使用空行来分隔相关语句块。省略额外的空行会加大代码阅读难度。比如,您可以在变量声明和代码之间有一行空行。
Good:
Function SpaceSample()
Dim counter As Integer
If counter = 0 Then
...
End If
End Function
Bad:
Function SpaceSample()
Dim counter As Integer
If counter = 0 Then
...
End If
If counter = 0 Then
...
End If
End Function
在本例中,过多的空行造成了空行滥用,并不能使代码更易于阅读。
您应该使用2行空行来分隔方法实现或类型声明。
3.9.2. 空格
空格能够降低代码密度以增加可读性。以下是使用空格符的一些指导规范:
您应该像如下般在一行代码中使用空格。
Good:
CreateFoo() ' 在函数名和括号之间不使用空格
Method(myChar, 0, 1) ' 在逗号之后使用一个空格
x = Array(Index) ' 在括号内部不使用空格
While (x = y) ' 在控制语句后使用一个空格
If (x = y) Then ' 使用一个空格来分隔操作
Bad:
CreateFoo () ' 在函数名和括号之间有空格
Method(myChar,0,1) ' 在逗号之后没有空格
x = Array( Index ) ' 在括号内部使用空格
While(x = y) ' 在控制语句后没有空格
If (x=y) Then ' 没有空格来分隔操作
3.10. 大括号
√一定要使用奥尔曼风格的大括号。
奥尔曼风格是以艾瑞·奥尔曼命名的,有时也被称为"ANSI风格"。该风格将大括号与相关代码置于下一行内,与控制语句的缩进相同。大括号内的语句缩进一个等级。(注:VB中不使用大括号,而是使用结束标志来组织代码块)
Good:
Function MyTest()
If foo.BorderStyoe = BorderStyle.None Then
...
End If
End Function
Bad:
Function MyTest()
If foo.BorderStyoe = BorderStyle.None Then
...
End If
End Function
√应该在即使是单行条件式的情况下也使用大括号。这样做使得将来增加条件式更简便,并减少制表符引起的歧义。
Good:
If x>5 Then
y = 0
End If
Bad:
If x>5 Then y = 0
3.11. 注释
√应该使用注释来解释一段代码的设计目的。一定不要让注释仅仅是重复代码。
Good:
' 确定系统是否运行在windows vista 或更新的操作系统(major version >=6),因为它们支
'持令牌环,但以前的版本(major version < 6)不支持。
Bad:
'下面的代码将变量i设置为数组的起始值。然后它们循环数组中每一项。
3.11.1. 内联代码注释
√内联注释应该在单独的行,并与所描述的代码具有相同的缩进。在其之前需要放置一个空行。其之后不需要空行。描述代码块的注释应该置于单独的行,与所描述的代码具有相同的缩进。其之前和之后都有一个空行。举例:
当内联注释只为结构体,类成员变量,参数和较短语句做描述时,则内联注释允许出现在和实际代码的同一行。在本例中,最好将所有变量的注释对齐。
CreateFoo() ' 在函数名和括号之间不使用空格
Method(myChar, 0, 1) ' 在逗号之后使用一个空格
x = Array(Index) ' 在括号内部不使用空格
√应该为那些仅通过阅读很难理解其意图的代码添加注释。
3.11.2. 文件头注释
√一定要为每一份手写代码(不是编码工具自动生成的代码)文件加入文件头注释。
文件头注释模板:
'***************************** 模块头*******************************\
' Module Name: 用户管理模块
' Project: 人事管理系统
' Copyright (c) My Company name
'
' 文件描述
'
' 这个源码是受到XXX公司许可的
' 参见http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
' XXX公司保持其所有权
' ……
'***************************************************************************/
3.11.3. 类注释
√应该为每一个重要的类或结构体作注释。注释的详细程度应该视代码的用户群而定。
' <summary>
' <Class description>
'</summary>
3.11.4. 函数注释
√应该为所有重要的Public或非Public函数作注释。注释的详细程度应该视代码的用户群而定。
√VB.NET 使用 .NET 描述性 XML 文档化注释。在一般情况下,至少需要一个<summary>元素,一个<parameters>元素和<returns>元素。会抛出异常的方法应使用<exception>元素来告知使用者哪些异常会被抛出。
' <summary>
' <Function description>
' </summary>
' <param name="Parameter name">
' <Parameter description>
' </param>
' <returns>
' <Description of function return value>
' </returns>
' <exception cref="<Exception type>">
' <Exception that may be thrown by the function>
' </exception>
任何调用失败会带来副作用的方法或函数,都需要清楚地在注释中描述清楚副作用的后果。一般而言,代码在发生错误或失败时不应该有副作用。当出现副作用时,在编写代码时应该有清楚的理由。
3.11.5. 将代码注释掉
√当您用多种方法实现某一项功能时,将代码注释掉便是必须的。除了第一个方法,其余实现方法都会被注释掉。使用 [-or-] 来分隔多个方法。举例,
' 第一个解决方案
DemoSolution1();
' [-or-]
' 第二个解决方案
'DemoSolution2();
3.11.6. TODO 待办注释
×一定不要在已发布的代码示例中使用TODO待处理的注释。每一个代码示例都必须完整,在代码中不能有未完成的任务。
3.12. 代码块
√一定要使用代码块声明。通过作用域或者功能性分类,将大量代码分组,会改善代码易读性和结构。
未完,待续......
本文标签:
转载请注明出处: http://www.itsec365.cn/?id=6
- 上一篇:网络信息安全学习平台练习--注入关第5题
- 下一篇:VB安全编码规范(续)