0

作为一个工作示例,我们可以处理以下代码:

    #include <sys/socket.h>

    #define size_t   SOCKET

    int receive_socket_data(SOCKET sock,//socket representing remote connection
                            unsigned long& version_number,//validPtr->version #
                            unsigned long& message_size,//validPtr->sizeof packet
                            char*& buf // where to copy data from packet
                           )
    {
       int nlen = 0;
       buf = NULL;

       // Receive version_number from the packet
       nlen = recv(sock, (char*) &version_number, sizeof(version_number), 0);
       if (nlen == 0 || nlen == -1) return ERROR_RECEIVING;
       version_number = ntohl(version_number);

       // Receive message_size from the entire packet 
       // (ulong + ulong + sizeof data)
       nlen = recv(sock, (char*) &message_size, sizeof(message_size), 0);
       if (nlen == 0 || nlen == -1) return ERROR_RECEIVING;
       message_size = ntohl(message_size);
       // Allocate a buffer to copy the data part of the packet
       buf = new char[message_size + 1 - 2 * sizeof(unsigned long)];
       buf[message_size - 2 * sizeof(unsigned long)] = '\0';

      // Copy the data part from the packet to the buffer
      if (recv(sock, (char*) buf, message_size-2*sizeof(unsigned long), 0) == -1)
         return ERROR_RECEIVING;

      return SUCCESS_RECEIVING;
    }

例如,我想到的事情是 operator new可能引发错误。
我不确定数组的索引计算是否也会导致问题。

4

1 回答 1

5

您可以帮助确定功能是否安全的一种方法是通过证明和测试以及防御性编码以及审查和经验。

防御性编码,因为任意代码不值得分析。使您的代码更易于分析和更安全,然后分析问题。您不能分析任意程序。即使是那些理论上可分析的,难度也会有很大差异。

证明,如正式证明您的功能是正确的。这需要充分理解和形式化您的代码与之交互的所有内容。请注意,防御性编码和简化代码使这在某种程度上成为可能。

测试,因为证明只在你认为代码在做什么的情况下才有效。您的代码模型可能不完整——哎呀,我什至会说它肯定是不完整的。您没有一个模型来说明当前未知的物理如何导致您的代码将运行的每个硬件中的位翻转,这是一个关于您的模型不完整的荒谬示例。几乎可以肯定的是,您的代码模型不完整的方式会变得不那么荒谬。

回顾一下,因为会有一些你没有想到的事情,并且通过让更有能力的人说服自己你的代码是正确的,可以增加你没有集体错过某些事情的机会。

经验,因为知道将注意力集中在哪里很重要。经验是记住你过去是如何搞砸的,或者亲眼目睹了别人的所作所为。

安全必须有多安全?一般来说,编写安全代码并不容易。这就是为什么编写密码系统的第一条规则是“不要”。

  1. 摆脱所有手动缓冲区管理。
  2. 在静态断言、动态断言和注释中包括形式证明,证明您的缓冲区大小算法没有缺陷。
  3. 包括每个被调用函数的正式描述,并包括为什么你的正式描述是准确的证据。包括每个被调用函数的单元测试,以验证它们是否按照您声称的方式执行,并以预期的方式失败。
  4. 切勿在没有检查和正式证明其格式正确的情况下取消引用指针或索引缓冲区。
  5. 不要做任何像预处理宏一样愚蠢的事情。找到一种方法来确保您正在编写的代码是已编译的代码:必须在您正在编写的令牌不是读取的内容的环境中进行证明是毫无意义的困难。
  6. 验证函数可能返回的每个可能值。即recv ——您检查 0 或 -1。如果它返回 -2 或 -(2^31) 会发生什么?保证不会发生?然后证明。
  7. 找一个真正的专家,让他们告诉你想做,或者付钱让他们去做。(我不是这方面的专家)

完成所有这些之后,您会想要攻击您的代码并尝试破坏它。

你会希望别人做同样的事情。

于 2012-11-29T16:00:09.300 回答