boost::asio::const_buffer 的安全重新分配

Secure deallocation of boost::asio::const_buffer

出于 PA:DSS 的目的,我需要确保 boost::asio::const_buffer(例如在 boost::asio::async_write 中)在超出范围时将被清零。

使用 STL 容器,我可以这样替换 allocator/deallocator:

    void deallocate(volatile pointer p, size_type n) {
        std::memset(p, 0, n * sizeof(T));
        ::operator delete(p);
    }

但是我不知道如何用 boost::asio::const_buffer 实现同样的效果,至少不会让 boost::asio::async_write 消耗它。我也不想重新发明轮子(如果有的话)。

简短回答:Asio 缓冲区不拥有它们的内存,因此它们也不应负责处理它

首先,你应该使用

std::memset(p, 0, n * sizeof(T));

使用类似 SecureZeroMemory instead: How-to ensure that compiler optimizations don't introduce a security risk?

的函数

我知道你有 volatile 因为这个原因,但它可能并不总是像你期望的那样受到尊重:

Your secure_memset function might not be sufficient. According to http://open-std.org/jtc1/sc22/wg14/www/docs/n1381.pdf there are optimizing compilers that will only zero the first byte – Daniel Trebbien Nov 9 '12 at 12:50

背景阅读:


关于 ASIO

确保您完全意识到 Boost Asio 缓冲区没有所有权语义。他们只引用另一个对象拥有的数据。

More importantly than the question posed, you might want to check that you keep around the buffer data long enough. A common pitfall is to pass a local as a buffer:

std::string response = "OK\r\n\r\n";
asio::async_write(sock_, asio::buffer(response), ...); // OOOPS!!!

This leads to Undefined Behaviour immediately.

IOW const_buffer是一个概念。有无数种方法可以在(您自己的)对象之上构建它:

documentation

A buffer object represents a contiguous region of memory as a 2-tuple consisting of a pointer and size in bytes. A tuple of the form {void*, size_t} specifies a mutable (modifiable) region of memory. Similarly, a tuple of the form {const void*, size_t} specifies a const (non-modifiable) region of memory. These two forms correspond to the classes mutable_buffer and const_buffer, respectively

那么,假设您有缓冲区类型

struct SecureBuffer
{
     ~SecureBuffer() { shred(); }
     size_t      size() const { return length_; }
     char const* data() const { return data_; }

     // ...
   private:
     void shred(); // uses SecureZeroMemory etc.

     std::array<char, 1024> data_ = {0};
     size_t length_ = 0u;
};

然后你可以简单地把它传递到你想使用它的地方:

SecureBuffer secret; // member variable (lifetime exceeds async operation)
// ... set data
boost::asio::async_write(sock_,
     boost::asio::buffer(secret.data(), secret.size()),
     /*...*/
    );