我想创建一个分配器,该分配器为内存提供以下属性:
这个想法是,它将包含用户不应访问的敏感信息(如许可证信息)。我已经在网上进行了常规研究,并向其他人询问了有关此问题的信息,但我找不到在此问题上找一个好的位置。
更新
Josh提到使用VirtualAlloc来设置对内存空间的保护。我创建了一个自定义分配器(如下所示),我发现使用VirtualLock函数限制了我可以分配的内存量。不过,这似乎是设计使然。由于我将它用于小物体,所以这不是问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| //
template<class _Ty>
class LockedVirtualMemAllocator : public std::allocator<_Ty>
{
public:
template<class _Other>
LockedVirtualMemAllocator<_Ty>& operator=(const LockedVirtualMemAllocator<_Other>&)
{ // assign from a related LockedVirtualMemAllocator (do nothing)
return (*this);
}
template<class Other>
struct rebind {
typedef LockedVirtualMemAllocator<Other> 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<pointer>( 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 );
}
}
}; |
并用于
1 2 3
| //a memory safe std::string
typedef std::basic_string<char, std::char_traits<char>,
LockedVirtualMemAllocato<char> > modulestring_t; |
Ted Percival提到了mlock,但是我还没有实现它。
我发现尼尔·弗格森(Neil Furguson)和布鲁斯·施耐尔(Bruce Schneier)的实用密码学也非常有帮助。
您无法真正防止内存访问。如果您以管理员或系统身份运行,则可以阻止分页,但不能阻止管理员或系统读取内存。即使您可以某种方式完全阻止其他进程读取您的内存(您不能这样做),另一个进程实际上仍可以向您的进程中注入新线程并以这种方式读取内存。
即使您可以某种方式完全锁定您的进程并保证操作系统永远不会允许其他人访问您的进程,您仍然没有完全的保护。整个操作系统可以在虚拟机中运行,可以随时暂停和检查该虚拟机。
您不能从系统所有者那里保护内存内容。好莱坞和音乐产业多年来一直对此感到痛苦。如果可能的话,他们已经在这样做了。
在Unix系统上,可以使用mlock(2)将内存页面锁定到RAM中,以防止页面被分页。
mlock() and mlockall() respectively lock part or all of the calling
processa€?s virtual address space into RAM, preventing that memory from
being paged to the swap area.
每个进程可以锁定多少内存是有限制的,可以用ulimit -l显示,以千字节为单位。在我的系统上,默认限制是每个进程32 kiB。
安装Libsodium,通过#include <sodium.h>
使用分配机制
保护堆分配
比malloc()和朋友慢,它们需要3或4个额外的虚拟内存页。
1
| void *sodium_malloc(size_t size); |
使用sodium_malloc()和sodium_allocarray()分配内存以存储敏感数据。使用这些堆防护之前,您需要先调用sodium_init()。
1
| void *sodium_allocarray(size_t count, size_t size); |
sodium_allocarray()函数返回一个指针,可以从该指针访问计数对象,每个计数对象都是内存的大小字节。它提供与sodium_malloc()相同的保证,但是还可以防止count * size超过SIZE_MAX时发生算术溢出。
这些功能在受保护的数据周围添加了保护页面,以使其在类似流血的情况下不太可能被访问。
此外,可以使用锁定存储操作(sodium_mprotect_noaccess(),sodium_mprotect_readonly()和sodium_mprotect_readwrite())更改以这种方式分配的存储区域的保护。
在sodium_malloc之后,您可以使用sodium_free()来解锁和释放内存。在实现的这一点上,请考虑使用后将内存清零。
使用后将内存清零
1
| void sodium_memzero(void * const pnt, const size_t len); |
使用后,敏感数据应被覆盖,但可以通过优化编译器或链接程序以静默方式删除memset()和手写代码。
sodium_memzero()函数将尝试从pnt开始有效地将len个字节清零,即使对代码进行了优化也是如此。
锁定内存分配
1
| int sodium_mlock(void * const addr, const size_t len); |
sodium_mlock()函数从addr开始至少锁定len个字节的内存。这可以帮助避免将敏感数据交换到磁盘。
1
| int sodium_mprotect_noaccess(void *ptr); |
sodium_mprotect_noaccess()函数使使用sodium_malloc()或sodium_allocarray()分配的区域不可访问。无法读取或写入,但会保留数据。该功能可用于使机密数据不可访问,除非特定操作实际需要时。
1
| int sodium_mprotect_readonly(void *ptr); |
sodium_mprotect_readonly()函数将使用sodium_malloc()或sodium_allocarray()分配的区域标记为只读。尝试修改数据将导致该过程终止。
1
| int sodium_mprotect_readwrite(void *ptr); |
sodium_mprotect_readwrite()函数将使用sodium_malloc()或sodium_allocarray()分配的区域标记为可读可写,在使用sodium_mprotect_readonly()或sodium_mprotect_noaccess()保护后。
如果您正在为Windows开发,则可以通过多种方法来限制对内存的访问,但是绝对不能屏蔽其他人。如果希望保守秘密,请阅读"编写安全代码",该书在一定程度上解决了该问题,但是请注意,您无法知道代码是在真实计算机上运行还是在虚拟机上运行。有很多Win32 API内容可以处理处理这种事情的加密,包括安全存储秘密-书中谈到了这一点。您可以查看在线Microsoft CyproAPI以获得详细信息。 OS设计人员意识到了这个问题,并且需要确保明文的安全(再次阅读"编写安全代码")。
Win32 API函数VirtualAlloc是操作系统级别的内存分配器。它允许您设置访问保护;您可以做的是将访问权限设置为PAGE_GUARD或PAGE_NOACCESS,然后在程序读取时将访问权限翻转为更友好的内容,然后再进行重置,但是如果有人真的很难窥视,那只是速度的障碍。保密。
总而言之,请查看您平台上的加密API,它们将比您自己破解某些东西更好地解决该问题。
让我们一次一点:
I want to create an allocator which
provides memory with the following
attributes:
这很公平。
1
| * cannot be paged to disk. |
那将很难。据我所知,您不能禁用虚拟分页,因为它是由操作系统处理的。如果有办法,那么您将在操作系统的肠子里摸索。
1
| * is incredibly hard to access through an attached debugger |
您可以通过PGP运行它,并将其加密存储在内存中,然后根据需要对其进行解密。巨大的性能打击。
The idea is that this will contain
sensitive information (like licence
information) which should be
inaccessible to the user. I have done
the usual research online and asked a
few other people about this, but I
cannot find a good place start on this
problem.
将所有敏感信息保留在机器之外。严重地。不要将敏感信息存储在内存中。编写一个自定义删除例程,该例程将自动从您执行的所有分配中删除所有数据。切勿一般性地访问装有敏感材料的机器。如果执行数据库访问,请确保在触发之前清除所有访问权限。仅具有特定登录权限的人员可以访问。没有一般的群组访问权限。
On a side note, what other methods are
there of accessing the memory of a
process other than attaching a
debugger?
转储内存。
您要查询的内容在操作系统级别进行处理。数据进入程序后,很容易被分页。
有动机的人可以使用硬件调试器来访问内存。
@graham
You could run it through PGP and store it encrypted in memory and unencrypt it as needed. Massive performance hit.
然后,您必须将密钥保存在内存中。这会使它变得更难一点,但绝对不是不可能的。任何有动力的人仍将设法从内存中获取数据。
您最好的选择是实现类似于.NET \\的SecureString类的内容,并务必小心将数据的任何纯文本副本归零(一旦发生异常,也不要忘记清理)被抛出)。使用std :: string等执行此操作的一种好方法是使用自定义分配器。
在Windows上,如果使用CryptProtectMemory(或对于较旧的系统使用RtlEncryptMemory),则加密密码存储在不可分页(内核?)的内存中。在我的测试中,这些功能相当快,尤其是。考虑到他们为您提供的保护。
在其他系统上,我喜欢使用Blowfish,因为它是速度和力量之间的良好结合。在后一种情况下,您必须在程序启动时随机生成自己的密码(河豚的熵为16个字节)。不幸的是,没有操作系统的支持,您可以采取很多措施来保护该密码,尽管您可能会使用一般的混淆技术将硬编码的salt值嵌入可执行文件中,以便与密码结合使用(每小部分)帮助)。
总体而言,该策略只是更广泛的纵深防御方法的一部分。还请记住,到目前为止,最常见的攻击媒介仍然是诸如缓冲区溢出和不清理程序输入之类的简单错误。
You cannot protect memory contents from the owner of the system.
Hollywood and the music industry have been aching for this for years.
If it were possible, they'd already be doing it.
您了解过Vista(及更高版本)受保护的进程(直接.doc下载)。我相信由操作系统实施的保护是娱乐界的礼貌。
@德里克公园
他只是更努力地说,不是没有可能。 PGP将使其变得更加困难,并非没有可能。
@Chris
Oh, but with trusted computing, you can use memory curtaining! :-P
但是您实际上必须愿意为别人拥有的计算机付费。 :p
@roo
I was really hoping that is was possible, and that I just hadn't found it yet. Your example just made me realise that that is exactly what we are trying to do - only allow access to files in the context of our program and so preserve the IP.
I guess I have to accept that there is no truly secure way to store someonea€?s files on another computer, especially if at some point access is allowed to that file by the owner.
那绝对是问题所在。只要您从不授予访问权限,就可以安全地存储内容,但是一旦授予访问权限,您的控制权就消失了。您可以使其更加困难,但这仅是全部。
@Derek:哦,但是有了可信的计算,您可以使用内存屏蔽! :-P devils-advocate>