当前位置:  开发笔记 > 编程语言 > 正文

C++中的安全内存分配器

如何解决《C++中的安全内存分配器》经验,为你挑选了4个好方法。

我想创建一个分配器,它提供具有以下属性的内存:

无法分页到磁盘.

很难通过附加的调试器访问

这个想法是,它将包含敏感信息(如许可证信息),这些信息应该是用户无法访问的.我在网上做了一般的研究,并向其他几个人询问了这个问题,但我找不到一个好的地方开始解决这个问题.

更新

Josh提到VirtualAlloc用来设置内存空间的保护.我创建了一个自定义分配器(如下所示)我发现使用VirtualLock它限制了我可以分配的内存量的函数.这似乎是设计的.由于我将它用于小物件,这不是问题.

//
template
class LockedVirtualMemAllocator : public std::allocator<_Ty>
{
public:
    template
    LockedVirtualMemAllocator<_Ty>& operator=(const LockedVirtualMemAllocator<_Other>&)
    {   // assign from a related LockedVirtualMemAllocator (do nothing)
        return (*this);
    }

    template
    struct rebind {
        typedef LockedVirtualMemAllocator other;
    };

    pointer allocate( size_type _n )
    {
        SIZE_T  allocLen = (_n * sizeof(_Ty));
        DWORD   allocType = MEM_COMMIT;
        DWORD   allocProtect = PAGE_READWRITE;
        LPVOID pMem = ::VirtualAlloc( NULL, allocLen, allocType, allocProtect );
        if ( pMem != NULL ) {
            ::VirtualLock( pMem, allocLen );
        }
        return reinterpret_cast( pMem );
    }
    pointer allocate( size_type _n, const void* )
    {
        return allocate( _n );
    }

    void deallocate(void* _pPtr, size_type _n )
    {
        if ( _pPtr != NULL ) {
            SIZE_T  allocLen = (_n * sizeof(_Ty));
            ::SecureZeroMemory( _pPtr, allocLen );
            ::VirtualUnlock( _pPtr, allocLen );
            ::VirtualFree( _pPtr, 0, MEM_RELEASE );
        }
    }
};

并被使用

 //a memory safe std::string
 typedef std::basic_string, 
                           LockedVirtualMemAllocato > modulestring_t;

Ted Percival提到了mlock,但我还没有实现.

我发现Neil Furguson和Bruce Schneier的实用密码学也很有帮助.



1> Derek Park..:

你无法真正防止内存访问.如果您以管理员或系统身份运行,则可能会阻止分页,但您无法阻止管理员或系统读取内存.即使你可以某种方式完全阻止其他进程读取你的内存(你不能),另一个进程仍然可以实际注入一个新线程进入你的进程并以这种方式读取内存.

即使您可以以某种方式完全锁定您的流程并保证操作系统永远不会允许其他人访问您的流程,您仍然没有完全的保护.整个操作系统可以在虚拟机中运行,可以随时暂停和检查.

无法保护系统所有者的内存内容.多年来,好莱坞和音乐界一直在为此做好准备.如果可能的话,他们已经在做了.



2> Ted Percival..:

在Unix系统上,你可以使用mlock(2)将内存页锁定到RAM中,防止它们被分页.

mlock()和mlockall()分别将部分或全部调用进程的虚拟地址空间锁定到RAM中,防止将内存分页到交换区域.

每个进程可以锁定的内存有一个限制,它可以显示ulimit -l为以千字节为单位并以千字节为单位进行测量.在我的系统上,默认限制为每个进程32 kiB.



3> graham.reeds..:

让我们一点一点:

我想创建一个分配器,它提供具有以下属性的内存:

这很公平.

* cannot be paged to disk.

那将是艰难的.据我所知,您无法禁用虚拟分页,因为它由操作系统处理.如果有办法,那么你将在操作系统的内容中进行探索.

* is incredibly hard to access through an attached debugger

您可以通过PGP运行它并将其加密存储在内存中并根据需要对其进行解密.大规模的性能打击.

这个想法是,它将包含敏感信息(如许可证信息),这些信息应该是用户无法访问的.我在网上做了一般的研究,并向其他几个人询问了这个问题,但我找不到一个好的地方开始解决这个问题.

将所有敏感信息保留在机器上.认真.不要将敏感信息存储在内存中.编写一个自定义删除例程,它将自动删除您执行的任何分配中的所有数据.绝不允许一般访问带有敏感材料的机器.如果执行数据库访问,请确保在触发之前清除所有访问权限.只允许具有特定登录的人员访问.没有一般组访问权限.

另外,除了附加调试器之外,还有哪些其他方法可以访问进程的内存?

转储内存.



4> Josh..:

如果您正在为Windows开发,有一些方法可以限制对内存的访问,但绝对阻止其他内容是不可行的.如果您希望保守秘密,请阅读编写安全代码 - 它可以解决此问题,但要注意您无法知道您的代码是在真机还是虚拟机上运行.有一堆Win32 API来处理加密处理这类事情,包括安全存储秘密 - 本书谈到了这一点.您可以查看在线Microsoft CyproAPI了解详细信息; 操作系统设计人员认识到这个问题以及保持明文安全的必要性(再次,阅读编写安全代码).

Win32 API函数VirtualAlloc是OS级别的内存分配器.它允许您设置访问保护; 你可以做的是设置访问权限,PAGE_GUARD或者PAGE_NOACCESS在你的程序读取时翻转访问更友好的东西,然后重置它,但如果有人真的很难偷看你的秘密,那只是一个速度突破.

总而言之,看看您平台上的加密API,它们将比您自己解决的问题更好地解决问题.

推荐阅读
雯颜哥_135
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有