The following guidelines provide several techniques for writing secure code.
Use code analysis tools.
Visual Studio Premium includes code analysis tools that can greatly increase the possibility of finding security bugs in your code. These tools find bugs more efficiently and with less effort. For more information, see one of the following topics.
Analyzing Managed Code Quality by Using Code Analysis
Analyzing C/C++ Code Quality by Using Code Analysis
Analyzing Database Code to Improve Code Quality
Conduct a security review.
The goal of every security review is either to enhance the security of products that have already been released, by providing updates, or to ensure that no new products are released until they are as secure as possible.
Do not randomly review code. Prepare in advance for the security review, and begin by carefully creating a threat model. If you do not, you can waste a lot of your team's time. Prioritize code that should receive the heaviest security review and which security bugs should be addressed.
Be specific about what to look for in a security review. When you look for specific problems, you usually find them. Look even harder if your team is finding a lot of security bugs in one area. It probably indicates an architecture issue that must be fixed. If you are finding no security bugs, that usually means that the security review was not performed correctly.
Hold security review as part of stabilization for each milestone, and a larger product-line push set by the management.
Use a code review checklist for security.
Regardless of your role in the software development team, it is useful to have a checklist to follow to ensure that the design and code meet a minimal bar.
Validate all user input.
If you allow your application to accept user input, either directly or indirectly, you must validate the input before you use it. Malicious users will try to make your application fail by tweaking the input to represent invalid data. The first rule of user input is: All input is bad until proven otherwise.
Be careful when you use regular expressions to validate user input. For complex expressions like e-mail addresses, it is easy to think that you are doing complete validation when you are not. Have peers review all regular expressions.
Strongly validate all parameters of exported and public application programming interfaces (APIs).
Ensure that all parameters of exported and public APIs are valid. This includes input that looks consistent but is beyond the accepted range of values, such as large buffer sizes. Do not use asserts to check the parameters for exported APIs because asserts will be removed in the release build.
Use the Windows cryptographic APIs.
Instead of writing your own cryptographic software, use the Microsoft cryptographic API that is already available. By using cryptographic API from Microsoft, developers are free to concentrate on building applications. Remember, encryption solves a small set of problems very well and is frequently used in ways that it was never designed for. For more information, see Cryptography Reference in the MSDN Library.
Buffer overruns.
A static buffer overrun occurs when a buffer declared on the stack is overwritten by copying data larger than the buffer. Variables declared on the stack are located next to the return address for the function’s caller. Buffer overruns can also occur in the heap, and these are just as dangerous. The usual culprit is unchecked user input passed to a function such as strcpy, and the result is that the return address for the function is overwritten by an address chosen by the attacker. Preventing buffer overruns is mostly a matter of writing a robust application.
Asserts to check external input.
Asserts are not compiled into retail builds. Do not use asserts to verify external inputs. All parameters for exported functions and methods, all user input, and all file and socket data must be carefully verified for validity and rejected if faulty.
Hard-coded user ID and password pairs.
Do not use hard-coded passwords. Modify the installer so that, when built-in user accounts are created, the administrator will be prompted for strong passwords for each account. This way, the security of the customer's production-level systems can be maintained.
Using encryption to solve all security issues.
Encryption solves a small set of problems very well and is frequently used in ways that it was never designed for.
Canonical file paths and URLs.
Avoid situations where the location of a file or a URL is important. Use file system ACLs instead of rules based on canonical file names.
Review all old security defects in your application.
Become knowledgeable about security mistakes that you made in the past. Frequently, code is written in repeated pattern. Therefore a bug in one location by one person might indicate the same bug in other locations by other people.
Review all error paths.
Frequently, code in error paths is not well tested and does not clean up all objects, such as locks or allocated memory. Carefully review these paths and, as needed, create fault-injection tests to exercise the code. For more information, see the "Input Validation" section of Design Guidelines for Secure Web Applications and the "Input Validation" section of Architecture and Design Review for Security in the MSDN library.
Administrator privileges for your application to run.
Applications should run with the least privilege necessary to get the work done. If a malicious user finds security vulnerability and injects code into your process, the malicious code will run with the same privileges as the host process. If the process is running as an administrator, the malicious code runs as an administrator. For more information, see Developing Software in Visual Studio .NET with Non-Administrative Privileges in the MSDN Library.
Threat Modeling
下列准则提供几项编写安全代码的技术。
使用代码分析工具。
Visual Studio 高级版包括代码分析工具,可以大大增加找到代码中的安全 Bug 的可能性。利用这些工具来查找 bug,可以事半功倍。有关更多信息,请参见下列主题之一。
使用代码分析来分析托管代码质量
使用代码分析来分析 C/C++ 代码质量
分析数据库代码以提高代码质量
进行安全检查。
每次安全检查的目标是通过提供更新增强已发布产品的安全性,或者确保没有新产品发布,产品已具有目前为止最好的安全性。
不要随意检查代码。应事先为安全检查做好准备,然后以认真创建一个威胁模型作为起始工作。如果不这样做,可能会浪费小组的大量时间。确定应接受最严格的安全检查的代码的优先顺序,以及应解决安全 bug 的优先顺序。
应确定要在安全检查中查找的具体问题。针对具体问题进行查找时,通常可以找到它们。如果小组在一个区域中找到大量安全 bug,则说明问题较为严重。这可能表示存在必须解决的体系结构问题。如果没有找到安全 bug,通常表示安全检查执行得不正确。
将安全检查作为保证每个里程碑稳定性的工作的一部分来完成,并将其作为管理部门确定的重要产品线推动因素。
使用检查表进行代码安全检查。
无论您在软件开发小组中的角色是什么,根据检查表进行工作都是很有用的,这样可以确保设计和代码满足某个最低目标。
验证所有用户输入。
如果您允许您的应用程序以直接或间接方式接受用户输入,则必须在使用输入之前对其进行验证。恶意用户会尝试通过调整输入以表示无效数据来使您的应用程序失败。用户输入的首要规则是:在经过验证之前,所有输入都是错误的。
使用正则表达式来验证用户输入时应务必小心。对于复杂的表达式(例如电子邮件地址),很容易认为您在执行完整的验证,而您实际并非如此。让其他同事检查所有正则表达式。
严格验证导出的和公共的应用程序编程接口 (API) 的所有参数。
确保导出的和公共的 API 的所有参数有效。这包括看起来一致但超出接受的值范围的输入,例如庞大的缓冲区大小。不要使用断言来检查导出的 API 的参数,因为发行版本中将移除断言。
使用 Windows 加密 API。
不要编写您自己的加密软件,应使用现成可用的 Microsoft 加密 API。通过使用 Microsoft 提供的加密 API,开发人员可以将精力集中于应用程序的生成。请记住,加密还涉及少数某些问题,并且通常以并非设计用途的方式使用。有关更多信息,请参见 MSDN Library 中的 Cryptography Reference(加密参考)。
缓冲区溢出。
如果在堆栈上声明的缓冲区被复制的大于缓冲区大小的数据覆盖,则会发生静态缓冲区溢出。在堆栈上声明的变量位于函数调用方的返回地址的旁边。堆中也会发生缓冲区溢出,这种情况很危险。常见的 culprit 是传递给函数(例如 strcpy)的未经检查的用户输入,结果是函数的返回地址被攻击者选择的某个地址覆盖。避免缓冲区溢出通常是编写可靠的应用程序的重要因素。
用断言来检查外部输入。
断言并未编译到销售版本中。不要使用断言来验证外部输入。必须仔细验证导出的函数和方法的所有参数、所有用户输入以及所有文件和套接字数据的有效性,如果发现有错,则予以拒绝。
硬编码的用户 ID 和密码对。
不要使用硬编码的密码。修改安装程序,使得创建内置用户帐户时,将提示管理员为每个帐户设置强密码。这样便可以维护客户的产品级别系统的安全。
使用加密功能可解决所有安全问题。
加密可以很好地解决少量问题,而且使用方式经常与其原定用途大相径庭。
规范化文件路径和 URL。
避免出现文件位置或 URL 很重要的情况。使用文件系统 ACL,而不要使用基于规范化文件名的规则。
检查应用程序中的所有以前的安全缺陷。
了解您在过去犯的安全错误。代码通常会以重复的模式编写。因此,某个人在某个位置所造成的 bug 可能表示其他人在其他位置中存在同样的 bug。
检查所有错误路径。
通常,错误路径中的代码没有得到很好的测试,并且不会清除所有对象,例如锁或分配的内存。仔细检查这些路径,如果需要,创建错误植入测试以执行该代码。有关更多信息,请参见 MSDN library 中“Design Guidelines for Secure Web Applications”(安全 Web 应用程序设计指南)的“Input Validation”(输入验证)部分,以及“Architecture and Design Review for Security”(体系结构和设计的安全检查)的“Input Validation”(输入验证)部分。
为要运行的应用程序设置管理员权限。
应使用使应用程序正常工作所需的最小特权来运行应用程序。如果恶意用户发现安全漏洞,并且在您的进程中注入代码,则恶意代码将使用与宿主进程相同的特权运行。如果进程以管理员身份运行,则恶意代码也将以管理员的身份运行。有关更多信息,请参见 MSDN Library 中的 Developing Software in Visual Studio .NET with Non-Administrative Privileges(使用非管理特权在 Visual Studio .NET 中开发软件)。
威胁模型
[原文链接]
1. http://msdn.microsoft.com/en-us/library/ms182020.aspx
2. http://msdn.microsoft.com/zh-cn/library/ms182020.aspx