发信人: netman.bbs@cs3.xmu.edu.cn (邂逅), 信区: cnhacker
标  题: 程序员安全(6)
发信站: cs3 BBS (Sun Jun 15 23:24:13 1997)
转信站: Lilac!ustcnews!ustcnews!sjtunews!cs3
出  处: cs3.xmu.edu.cn

3.写安全的C程序
    一般有两方面的安全问题,在写程序时必须考虑:
      (1)确保自己建立的任何临时文件不含有机密数据,如果有机密数据,设置
         临时文件仅对自己可读/写.确保建立临时文件的目录仅对自己可写.
      (2)确保自己要运行的任何命令(通过system(),popen(),execlp(),
         execvp()运行的命令)的确是自己要运行的命令,而不是其它什么命
         令,尤其是自己的程序为SUID或SGID许可时要小心.
    第一方面比较简单,在程序开始前调用umask(077).若要使文件对其他人可
    读,可再调chmod(),也可用下述语名建立一个"不可见"的临时文件.
         creat("/tmp/xxx",0);
         file=open("/tmp/xxx",O_RDWR);
         unlink("/tmp/xxx");
    文件/tmp/xxx建立后,打开,然后断开链,但是分配给该文件的存储器并未删
    除,直到最终指向该文件的文件通道被关闭时才被删除.打开该文件的进程
    和它的任何子进程都可存取这个临时文件,而其它进程不能存取该文件,因
    为它在/tmp中的目录项已被unlink()删除.
    第二方面比较复杂而微妙,由于system(),popen(),execlp(),execvp()执行
    时,若不给出执行命令的全路径,就能"骗"用户的程序去执行不同的命令.因
    为系统子程序是根据PATH变量确定哪种顺序搜索哪些目录,以寻找指定的命
    令,这称为SUID陷井.最安全的办法是在调用system()前将有效UID改变成实
    际UID,另一种比较好的方法是以全路径名命令作为参数.execl(),execv(),
    execle(),execve()都要求全路径名作为参数.有关SUID陷井的另一方式是
    在程序中设置PATH,由于system()和popen()都启动shell,故可使用shell句
    法.如:
         system("PATH=/bin:/usr/bin cd");
    这样允许用户运行系统命令而不必知道要执行的命令在哪个目录中,但这种
    方法不能用于execlp(),execvp()中,因为它们不能启动shell执行调用序列
    传递的命令字符串.
    关于shell解释传递给system()和popen()的命令行的方式,有两个其它的问
    题:
       *shell使用IFS shell变量中的字符,将命令行分解成单词(通常这个
    shell变量中是空格,tab,换行),如IFS中是/,字符串/bin/ed被解释成单词
    bin,接下来是单词ed,从而引起命令行的曲解.

    再强调一次:在通过自己的程序运行另一个程序前,应将有效UID改为实际的
    UID,等另一个程序退出后,再将有效UID改回原来的有效UID.

    SUID/SGID程序指导准则
    (1)不要写SUID/SGID程序,大多数时候无此必要.
    (2)设置SGID许可,不要设置SUID许可.应独自建立一个新的小组.
    (3)不要用exec()执行任何程序.记住exec()也被system()和popen()调用.
       . 若要调用exec()(或system(),popen()),应事先用setgid(getgid())
         将有效GID置加实际GID.
       . 若不能用setgid(),则调用system()或popen()时,应设置IFS:
         popen("IFS=\t\n;export IFS;/bin/ls","r");
       . 使用要执行的命令的全路径名.
       . 若不能使用全路径名,则应在命令前先设置PATH:
         popen("IFS=\t\n;export IFS;PATH=/bin:/usr/bin;/bin/ls","r");
       . 不要将用户规定的参数传给system()或popen();若无法避免则应检查
         变元字符串中是否有特殊的shell字符.
       . 若用户有个大程序,调用exec()执行许多其它程序,这种情况下不要将
         大程序设置为SGID许可.可以写一个(或多个)更小,更简单的SGID程序
         执行必须具有SGID许可的任务,然后由大程序执行这些小SGID程序.
    (4)若用户必须使用SUID而不是SGID,以相同的顺序记住(2),(3)项内容,并
       相应调整.不要设置root的SUID许可.选一个其它户头.
    (5)若用户想给予其他人执行自己的shell程序的许可,但又不想让他们能
       读该程序,可将程序设置为仅执行许可,并只能通过自己的shell程序来
       运行.
    编译,安装SUID/SGID程序时应按下面的方法
    (1)确保所有的SUID(SGID)程序是对于小组和其他用户都是不可写的,存取
       权限的限制低于4755(2755)将带来麻烦.只能更严格.4111(2111)将使
       其他人无法寻找程序中的安全漏洞.
    (2)警惕外来的编码和make/install方法
       . 某些make/install方法不加选择地建立SUID/SGID程序.
       . 检查违背上述指导原则的SUID/SGID许可的编码.
       . 检查makefile文件中可能建立SUID/SGID文件的命令.

--
※ 来源:·古庙钟声 cs3.xmu.edu.cn·[FROM: freedom@cs3.xmu.edu.]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:2.499毫秒