安全程式码撰写

安全程式码撰写(Secure coding)是依照安全指引开发电脑软体,避免引入漏洞的软体开发实务。设计缺陷、程序错误及逻辑谬误是最常被利用软体漏洞的主要原因[1]。若识别出这些不安全的程式码撰写实务,教育程式设计师改用较安全的软体写法,组织可以有主动的措施,在程式布置之前就消除或大幅减少软体漏洞[2]

有些研究者建议,为了有效的面对网路安全相关的威胁,应该在程式码撰写时加入适当的安全性。若在软体设计时就已考虑安全性,这可以避免内部人士的攻击,也减少和应用程式安全有关的威胁[3]

避免缓冲区溢出

缓冲区溢出是常见的软体安全漏洞,若程序要在固定长度的缓冲区储存超过其大小的资料,就会出现此一问题。例如,有8个位置可以储存资料,但程式却试著要储存9个资料,就会出现问题。缓冲区溢出会覆写到邻近位置的记忆体,造成安全漏洞(栈缓冲区溢出)或是程式中止执行(例如出现记忆体区段错误[1]

以下是一个容易出现缓冲区溢出的C语言程式例子


int vulnerable_function(char * large_user_input) {
    char dst[SMALL];
    strcpy(dst, large_user_input);
}

若使用者输入的资料比缓冲区的大小要大,就会出现缓冲区溢出。

若要修正此一问题,可以用strncpy来避免缓冲区溢出

int secure_function(char * user_input) {
    char dst[BUF_SIZE];
    // copy a maximum of BUF_SIZE bytes
    strncpy(dst, user_input, BUF_SIZE);
}

另一种作法是用malloc英语malloc指令,在heap里动态分配记忆体

char * secure_copy(char * src) {
    size_t len = strlen(src);
    char * dst = (char *) malloc(len + 1);
    if (dst != NULL) {
        strncpy(dst, src, len);
        // append null terminator 
        dst[len] = '\0';
    }
    return dst;
}

在上述的程式片段里,程式设法将src的内容复制到dst,不过也会检查malloc的传回值,确定有足够的记忆体可以分配记忆体给dst。

避免格式字串攻击

格式字串攻击英语Format string attacks是恶意用户在输入一些会提供给格式设定函式(如printf())的资料时,输入特殊的内容,让函式的动作异常。此攻击会破坏性的读取或写入呼叫堆叠

C语言的printf函式会将输出写到stdout。若其引数的格式有误时,会造成一些严重的安全错误。以下是一个格式字串攻击的例子。

int vulnerable_print(char * malicious_input) {
	printf(malicious_input);
}

像是"%s%s%s%s%s%s%s"就属于恶意输入,会因为不正确的记忆体读取而让程式崩溃。

避免整数溢位

整数溢位会出现在整数运算的结果太大,用规划的记忆体空间无法正确表示的情形。若程式没有检查整数运算的结果,设法避免整数溢位,可能会造成软体错误或是漏洞。

以下是C++的函式,原始目的是要确认x和y相加的结果小于等于已定义好的数值MAX:

bool sumIsValid_flawed(unsigned int x, unsigned int y) {
	unsigned int sum = x + y;
	return sum <= MAX;
}

这段程式的问题是在进行整数的加法之后才进行检查。若x和y的和大于unsigned int可以表示的最大值,在进行加法之后就已出现溢位,因此虽然x和y的和大于MAX,但是其溢位后的结果可能会小于MAX。

以下也是检查溢位的程式,加上了检查x和y的和是否有大于等于x,y二个数值的判断,因为x和y是无号数整数,二者的和不会小于其中的任一数字。若是若计算出来的和小于任一数字,就代表已经溢位了。

bool sumIsValid_secure(unsigned int x, unsigned int y) {
	unsigned int sum = x + y;
	return sum >= x && sum >= y && sum <= MAX;
}

避免目录遍历

目录遍历是由不可靠来源提供的路径产生的漏洞,该路径造成了未授权的伺服器目录或是档案存取。

例如,考虑一个接受档案名称,读取文章的脚本,脚本会读档案名称输入,之后进行处理。这样脚本可能会用类似以下的的URL 来找有关dog food的文章。

https://www.example.net/cgi-bin/article.sh?name=dogfood.html

若此脚本没有输入检查,相信使用者输入的档案都是有效的,恶意使用者可能会产生以下的URL来取得网站伺服器的组态:

https://www.example.net/cgi-bin/article.sh?name=../../../../../etc/passwd

若是在类Unix系统中,这可能会泄漏/etc/passwd档,其中包括了用户ID用户名称家目录路径等。(SQL注入也是类似情境下的攻击)。

相关条目

参考资料

  1. ^ 1.0 1.1 Viega, John; Gary McGraw. Building Secure Software: How to Avoid Security Problems the Right Way. MAddison-Wesley Professional. 2001: 528. ISBN 978-0201721522. 
  2. ^ Taylor, Blair; Azadegan, Shiva. Threading secure coding principles and risk analysis into the undergraduate computer science and information systems curriculum. Proceedings of the 3rd annual conference on Information security curriculum development. InfoSecCD '06. Kennesaw, Georgia: Association for Computing Machinery. 2006-09-22: 24–29. ISBN 978-1-59593-437-6. S2CID 2452783. doi:10.1145/1231047.1231053. 
  3. ^ Russell L, Jones. Secure Coding: Building Security into the Software Development Life Cycle. Information Systems Security. Dec 2004. ProQuest 229507883. 

参考书目

  • Taylor, Art; Brian Buege; Randy Layman. Hacking Exposed J2EE & Java. McGraw-Hill Primis. 2006: 426. ISBN 0-390-59975-1.