这篇文章来自于《Writing secure code》的附录一,我借了这本书很久,但是一直没有怎么看,我想还是将来有机会再来看吧。但我觉得附录一是很好的内容,就看了这部分并写了读后感。
对于API的使用,我先前就集中精力注意过,然而限于自己的视野,始终不够全面。这次就是一个很好的提高的机会。
1. 有缓冲区溢出问题的API
在c运行时库有很多这样的函数。
strcpy,wcscpy,lstrcpy,_tcscat,_mbscpy和strcat,wcscat,lcscat,_tcscat,_mbscat 他们不检查目标缓冲区大小,也不检查null或者其他无效指针。可以使用”n”版本代替,并检查目标和源缓冲区有效性。
strncpy,wcsncpy,lstrcpyn,_tcsncpy和mbsnbcpy 不能保证这些函数会用null来结束目标缓冲区,他们也不检查null或者其他无效指针。我通常使用这样的API时,会这样做:生成目标缓冲区,并清零;检查源缓冲区有效性;最大拷贝长度设置为目标缓冲区大小-1。
strncat,wcscat,_tcsncat和_mbsnbcat 这些函数并不知道缓冲区大小是多少而是关注拷贝的长度,并不知道源和目的缓冲区是否以null结尾。
memcpy和CopyMemory 目标缓冲区必需足够大,以便能够存储长度参数中制定的字节数,。
Sprintf和swprintf,这是两个足够恐怖的函数,一旦稍有不慎,则可能缓冲区溢出。
_snprintf和_snwprintf 这些函数可能不会用null结束目标缓冲区。用于行为根据平台而定,这需要考虑平台兼容性。
printf,_printf,_snprintf,vprintf,vsprintf,考虑因为参数原因导致的危险。
strlen,_tcslen,_mbslen,wcslen 这些函数都不能合适地处理非null结束的缓冲区,很可能导致访问越界。
gets,同样非常恐怖的函数,完全不能预期外界的输入。使用fgets或者循环使用getc来代替。
scanf,_tscanf,wscanf 很难控制输入的长度,可以使用类型%32S方式来规避。
输入流同样是难以限定输入的,只能使用std::cin.width()来规避。
MultiByteToWideChar这个函数的最后一个参数值得注意。
2. 有擅用名称问题的API
CreateDirectory、CreateEvent、CreateFile、CreateFileMapping、CreateHardLink、CreateJobObject、CreateMailSlot、CreateMutex、CreateSemaphore等API或者封装了这些函数类。
任何用一个名字创建对象的调用都有擅用名称的倾向。别的程序可以猜测程序的行为,例如,别的文件可以通过事先创建一个同名文件来获取该文件的控制权。
对于文件或者对象来说,永远不要假设它们不存在。
3. 有特洛伊问题的API
有的函数在不正确使用的时候会导致应用程序加载非预期的代码。CreateProcess,CreateProcessAsUser,CreateProcessWithLogon,WinExec,ShellExcute,LoadLibrary,LoadLibraryEx和SearchPath。此类函数经常涉及到加载程序的问题,如果使用相对路径的话,程序会首先到当前目录下搜索,如果没有找到的话,会在系统的搜索路径下查找。攻击者此时就会有了可乘之机,可以将一个同名的程序放在优先搜索的目录下,这样攻击程序就会优于正常程序,而被加载。建议使用完整路径,路径可以配置在注册表中。
4. 窗口样式和控件类型
在Windows中到处都是窗体和控件。很多涉及到缓冲区的地方都需要小心。
5. 模拟API
这节看不懂,没有接触过模拟,也没有太多兴趣搞清楚。
6. 有拒绝服务攻击问题的API
InitializeCriticalSection和EnterCriticalSection这些函数在低内存的情况下会抛出异常。最好使用对象锁来处理这个问题。
在堆栈内存溢出的时候会出现异常,如果确认异常是STATUS_STACK_OVERFLOW需要调用_resetkoflw。
TerminateThread和TerminateProcess都不是好的东东,没事不要调用。
7. 网络API问题
永远不要在临界区进行网络调用。如果使用网络就要认为它始终充满敌意。Bind如果将参数设置成INADDR_ANY(任何接口)时要小心,可能出现Socket劫持的危险。所谓服务器劫持,就是一个端口可以由多个程序绑定,且绑定某个固定Ip的优先级高于INADDR_ANY的优先级,导致服务器的消息被别的程序收取。可以选择SO_EXCLUSIVEADDRUSE,来规避这个问题。当如果选择这个选项,在SOCKET未正常关闭的情况下,下次启动会失败。
Recv阻塞收取的效率不高,选择异步Socket可能会好很多;Send的时候需要检查返回值。
8. 其他API
不要使用IsBadXXX类型的API。CopyFile和MoveFile使用需要谨慎,存在文件访问控制的问题。