我正在为应用程序做一些基本的安全工作。用户登录并通过活动目录验证其凭据。在程序中某些时候用户请求更改导致程序重新启动。由于这不是单个实例程序,我只需启动另一个实例并关闭当前实例,一切都很好。
但是,用户不满意每次重新启动时都必须重新登录。因此,我使用SecureString将一些基本安全性拼凑在一起以将密码存储在应用程序中,然后如果应用程序重新启动,它会解密密码并使用Rijndael算法的实现重新加密(来自codeproject的非常基本的)。然后它将用户名和加密密码作为命令行参数传递给正在启动的新实例。 (需要进行加密,因为在任何“wmic进程”调用时,他们都会显示密码。)新实例对其进行解密并再次以静默方式对活动目录进行验证,然后将其作为正常情况下的SecureString存储。
我对一般安全实践不太熟悉,但我对从解密方法返回密码的部分感到有点紧张。它本身并没有存储在任何变量中,而是在活动目录验证请求中进行调用。但是我仍然不确定它是否可以在内存中访问,或者它只是挂在寄存器中。
这不需要是有史以来最大的安全性,对于任何能够轻松访问内存内容并查看以明文形式保存的密码的人来说,这只是一种沮丧。
非常感谢!
答案 0 :(得分:4)
你的攻击模型是什么?
所以我想我的建议是放弃你正在做的所有服务器端加密,因为你认为服务器是安全的。没有人可以访问你的服务器的内存,如果有人你可能会被拥有。
答案 1 :(得分:1)
在.NET应用程序中,函数返回值被推送到"评估堆栈",它位于进程内的受保护内存中。但是,您正在谈论一个字符串,而这是一个引用类型,因此评估堆栈上的内容是指向该字符串在堆上的位置的指针。堆内存相对不安全,因为它可以共享,并且因为只要GC不认为需要收集它就会存在,这与高度不稳定的评估或调用堆栈不同。但是,要访问堆内存,必须共享该内存,并且您的攻击者必须拥有一个拥有操作系统和CLR权限的应用程序才能访问该内存,并知道该在哪里查看。
如果攻击者具有此类访问权限,则可以通过 更轻松的方式从计算机获取明文密码。键盘记录程序可以查看输入的密码,或者另一个窥探者可以在GDI UI的非托管侧观察实际句柄,并查看实际显示在Windows GUI中的文本框获取明文值(' s只在显示屏上混淆了)。所有这些都没有试图破解.NET的代码访问安全性或受保护的内存。
如果攻击者拥有这种控制权,那么你就输了。因此,这应该是第一道防线;确保客户端计算机上没有此类恶意软件,并且用户尝试登录的客户端应用程序实例未被破解的类似替换。
就实例之间的模糊密码存储而言,如果你担心mem-snooping,像Rijndael这样的对称算法就无法防范。如果您的攻击者可以看到客户端计算机的内存,他就知道用于加密它的密钥,因为您的应用程序需要知道它才能解密它;因此它将被硬编码到客户端应用程序中,或者它将被存储在安全字符串附近。同样,如果您的攻击者具有这种控制权,那么如果您在客户端进行身份验证,则会丢失。
相反,我会在物理和电子安全的计算机上使用服务层来提供您的应用程序的任何功能,如果被攻击者误用(主要是数据检索/修改),这些功能对您有害。该服务层既可用于验证,也可用于授权用户执行客户端应用程序允许的任何内容。
请考虑以下事项:
现在,当您的客户端应用程序关闭时,所有"会话状态&#34>在客户端和服务器之间丢失;会话令牌对任何其他协商通道无效。所以,你已经失去了身份验证;连接的下一个客户可以是任何人,无论他们是谁。这就是"转移令牌"进来:
在这里擦;这个系统依靠一个秘密密码,除了用户的心灵之外没有任何持久密码,没有后门;管理员无法检索客户端应用程序丢失的密码。此外,AD凭证(必须更改时)只能在客户端应用程序中更改;在Windows登录时,用户无法通过AD本身强制更改其密码,因为这样做会破坏他们进入客户端应用程序所需的身份验证方案(加密的凭据将不再起作用,并且客户端应用程序需要凭据来重新加密新的凭据)。如果您以某种方式在AD中拦截此验证,并且客户端的应用凭据是AD凭据,您可以自动更改用户应用中的凭据,但现在您使用一组凭据来混淆了同一套凭证,如果知道了这个秘密,你就会被清除。
最后,这种安全系统的变体仅仅依据一个原则;服务器当前没有被攻击者攻陷。有人可以进入,下载离线数据,然后他们就会卡住;但是如果他们可以安装一些内容来监控内存或流量,那么你就会受到冲击,因为当凭据(用户名/密码哈希或传输令牌/硬件ID)进入并经过验证时,攻击者现在有了解密密钥用户的AD凭据。通常情况下,客户端从不发送解密密钥,只发送散列密码的验证一半,然后服务器发回加密的凭证;但是,您正在考虑客户端比服务器更大的安全风险,所以只要这是真的,最好尽可能在客户端保留尽可能少的明文。
答案 2 :(得分:0)
看看这个: Password Salt (Wikipedia)
总结方法: