安全地保存配置项

转载 2006年06月01日 19:26:00
在作具体的应用的时候,我们通常都会在config文件中保存一些重要的配置,比如帐号和密码,以及连接串。为了安全,我们需要将其加密后再写入配置文件,以免被居心叵测者非常容易地获取到。.Net Framework提供了几种对称加密算法,比如DES3DES等,我们可以使用这些算法将敏感的配置项加密。然而,对称加密的天然问题就是密钥的管理——加密算法都是公开的,如果密钥泄漏(比如有人把密钥写在代码中,那完全可以通过反编译代码来得知密钥),那加密就形同虚设了。所以我们需要把密钥保存在相对安全的地方。

可行的做法为:

1、  使用Aspnet_setreg.exe 工具。此工具使用DPAPI来加密和解密数据,它可以把你需要保护的数据保存在注册表,它受DACLdiscretionary access control list)保护,在配置文件中只需要指明注册表键的位置。有一篇How to讲解了如何使用此Aspnet_setreg.exe 工具。在我的随笔系统安全简述中对DPAPI有简单的讲述——DPAPIData Protection Application Programming Interface),一个保护密钥的对策。DPAPI使用用户的登录密码加密和解密数据。数据保护过程:(1)生成一个强健的Key,称为主钥,它受用户的密码保护;(2)使用基于口令的密钥生成过程由用户密码生成一个密钥;(3)这个由口令生成的密钥用来加密主钥,它被存储在由计算机上的活动目录生成的用户概述中。安全地存储登录证明,比如用户名和密码,在磁盘上,是安全应用地一个重要方面。DPAPI是一个系统提供的数据保护服务,是一个安全地存储用户证明的解决方案。

2、  直接使用DPAPI.Net framework提供的加密算法。提供一个keykey越强就越安全),使用DPAPI加密,把它存储在注册表中,然后我们可以使用此key来加密和解密数据了——加密和解密算法我们可以选择.Net framework提供的3DESDES比较脆弱)。最后,我们把加密过的配置项(如连接串)写入config文件即可。

使用DPAPI时,需要我们提供足够强健的key,否则安全性会降低。另外,如果侵入者获得了系统的管理员权限的话,那这些安全措施都将失效,因为管理员有权限读取我们存入注册表的key

 

下面是使用DPAPI加密和解密数据的例子:
[DllImport("Crypt32.dll", SetLastError=true
CharSet
=System.Runtime.InteropServices.CharSet.Auto)] 
    
private static extern bool CryptProtectData( 
      
ref DATA_BLOB pDataIn, 
   String szDataDescr, 
      
ref DATA_BLOB pOptionalEntropy, 
   IntPtr pvReserved, 
      
ref CRYPTPROTECT_PROMPTSTRUCT 
   pPromptStruct, 
      
int dwFlags, 
      
ref DATA_BLOB pDataOut); 
     
   [DllImport(
"kernel32.dll"
      
CharSet
=System.Runtime.InteropServices.CharSet.Auto)] 
    
private unsafe static extern int FormatMessage(int 
dwFlags, 
      
ref IntPtr lpSource, 
      
int dwMessageId, 
      
int dwLanguageId, 
      
ref String lpBuffer, 
      
int nSize, 
   IntPtr 
*Arguments); 
 
   [StructLayout(LayoutKind.Sequential, 
CharSet
=CharSet.Unicode)] 
      
internal struct DATA_BLOB 
   

      
public int cbData; 
      
public IntPtr pbData; 
   }
 
 
   [StructLayout(LayoutKind.Sequential, 
CharSet
=CharSet.Unicode)] 
      
internal struct CRYPTPROTECT_PROMPTSTRUCT 
   

      
public int cbSize; 
      
public int dwPromptFlags; 
      
public IntPtr hwndApp; 
      
public String szPrompt; 
   }
 
    
static private IntPtr NullPtr = ((IntPtr)((int)(0))); 
    
private const int CRYPTPROTECT_UI_FORBIDDEN = 0x1
    
private const int CRYPTPROTECT_LOCAL_MACHINE = 0x4
 
    
public enum Store {USE_MACHINE_STORE = 1
USE_USER_STORE}

 
    
private Store store; 
 
    
public void DataProtector(Store tempStore) 
   

   store 
= tempStore; 
   }
 
 
    
public byte[] Encrypt(byte[] plainText, byte[] 
optionalEntropy) 
 
   

      
bool retVal = false
   DATA_BLOB plainTextBlob 
= new DATA_BLOB(); 
   DATA_BLOB cipherTextBlob 
= new DATA_BLOB(); 
   DATA_BLOB entropyBlob 
= new DATA_BLOB(); 
   CRYPTPROTECT_PROMPTSTRUCT prompt 
= new 
CRYPTPROTECT_PROMPTSTRUCT(); 
   InitPromptstruct(
ref prompt); 
      
int dwFlags; 
      
try 
     

       
try 
       

         
int bytesSize = plainText.Length; 
      plainTextBlob.pbData 
= 
Marshal.AllocHGlobal(bytesSize); 
         
if(IntPtr.Zero == plainTextBlob.pbData) 
         

           
throw new Exception("Unable to allocate 
plaintext buffer."); 
         }
 
      plainTextBlob.cbData 
= bytesSize; 
      Marshal.Copy(plainText, 
0
plainTextBlob.pbData, bytesSize); 
       }
 
       
catch(Exception ex) 
       

         
throw new Exception("Exception marshalling 
data. " + ex.Message); 
       }
 
       
if(Store.USE_MACHINE_STORE == store) 
       

      dwFlags 
= 
CRYPTPROTECT_LOCAL_MACHINE
|CRYPTPROTECT_UI_FORBIDDEN; 
          
         
if(null == optionalEntropy) 
         

       optionalEntropy 
= new byte[0]; 
         }
 
         
try 
         

           
int bytesSize = optionalEntropy.Length; 
       entropyBlob.pbData 
= 
Marshal.AllocHGlobal(optionalEntropy.Length);; 
           
if(IntPtr.Zero == entropyBlob.pbData) 

  

             
throw new Exception("Unable to 
allocate entropy data buffer."); 
           }
 
       Marshal.Copy(optionalEntropy, 
0
entropyBlob.pbData, bytesSize); 
       entropyBlob.cbData 
= bytesSize; 
         }
 
         
catch(Exception ex) 
         

           
throw new Exception("Exception entropy 
marshalling data. " + 
         ex.Message); 
         }
 
       }
 
       
else 
       

      dwFlags 
= CRYPTPROTECT_UI_FORBIDDEN; 
       }
 
     retVal 
= CryptProtectData(ref plainTextBlob, ""
ref entropyBlob, 
      IntPtr.Zero, 
ref prompt, dwFlags, 
         
ref cipherTextBlob); 
       
if(false == retVal) 
       

         
throw new Exception("Encryption failed. " + 
        
 GetErrorMessage(Marshal.GetLastWin32Error())); 
       }
 
        
       
if(IntPtr.Zero != plainTextBlob.pbData) 
       

      Marshal.FreeHGlobal(plainTextBlob.pbData); 
       }
 
       
if(IntPtr.Zero != entropyBlob.pbData) 
       

      Marshal.FreeHGlobal(entropyBlob.pbData); 
       }
 
     }
 
      
catch(Exception ex) 
     

       
throw new Exception("Exception encrypting. " + 
ex.Message); 
     }
 
      
byte[] cipherText = new byte[cipherTextBlob.cbData]; 
   Marshal.Copy(cipherTextBlob.pbData, cipherText, 
0
cipherTextBlob.cbData); 
   Marshal.FreeHGlobal(cipherTextBlob.pbData); 
      
return cipherText; 
   }
 
 
    
private void InitPromptstruct(ref 
CRYPTPROTECT_PROMPTSTRUCT ps) 

   ps.cbSize 
= 
Marshal.SizeOf(
typeof(CRYPTPROTECT_PROMPTSTRUCT)); 
   ps.dwPromptFlags 
= 0
   ps.hwndApp 
= NullPtr; 
   ps.szPrompt 
= null
   }
 
 
    
private unsafe static String GetErrorMessage(int 
errorCode) 
   

      
int FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100
      
int FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200
      
int FORMAT_MESSAGE_FROM_SYSTEM  = 0x00001000
      
int messageSize = 255
      String lpMsgBuf 
= ""
      
int dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | 
     FORMAT_MESSAGE_FROM_SYSTEM 
| 
     FORMAT_MESSAGE_IGNORE_INSERTS; 
   IntPtr ptrlpSource 
= new IntPtr(); 
   IntPtr prtArguments 
= new IntPtr(); 
      
int retVal = FormatMessage(dwFlags, ref ptrlpSource, 
errorCode, 
0
       
ref lpMsgBuf, messageSize, 
     
&prtArguments); 
      
if(0 == retVal) 
     

       
throw new Exception("Failed to format message for 
error code " + 
      errorCode + ""); 
     }
 
      
return lpMsgBuf; 
}
 

如何保证C++构造函数的安全性

C++的构造函数是一个比较特殊的函数
  • linqingwu75
  • linqingwu75
  • 2014年11月09日 20:39
  • 493

Java中list循环清除元素

因为大家都知道ArrayList,LinkedList没有使用synchronized对线程同步作任何处理,也就是说它们在同一时刻可以由多个线程访问,不是线程安全的,所以在移除的过程中会产生莫名奇妙的...
  • u010702229
  • u010702229
  • 2014年05月12日 12:53
  • 794

C++Primer第五版 7.3.1节练习

练习7.23:编写你自己的Screen类 答:见云盘程序 练习7.23.cpp练习7.24:给你的Screen类添加三个构造函数:一个默认的构造函数;另一个构造函数接受宽和高的值,然后将conten...
  • fengzhanghao23
  • fengzhanghao23
  • 2015年09月16日 07:19
  • 1084

C++调用外部应用程序的方法的整理总结

一、三个SDK函数:  WinExec,ShellExecute ,CreateProcess可以实现调用其他程序的要求,其中以WinExec最为简单,ShellExecute比WinExec灵活一...
  • u010648352
  • u010648352
  • 2017年03月16日 10:17
  • 86

单点登录(六):出现过的bug

1.PKIX path building failed:  原因:服务器不信任我们自己创建的证书 解决:往JDK中导入证书,注意需要导入到我们用的哪个cacerts文件,之前就是没有导入这个文件导...
  • u014077165
  • u014077165
  • 2015年02月01日 10:45
  • 2714

计算机软件配置项(转)

CSCI是计算机软件配置项(Computer Software Configuration Item)简称,在软件设计文档中经常用到。  配置与配置项    在配置管理中,“配置”和“配置项”是重要的...
  • yuer313
  • yuer313
  • 2011年05月16日 10:37
  • 3967

笔记本电脑中的安全问题及解决

随着网络安全事件的不断曝出,网络安全‍成了很多朋友比较关心的问题,不仅如此,计算机本地信息的安全同样十分重要,它直接关系着我们的数据安全。今天我们就来看看关于本地磁盘或者文件加密的方法,希望能够帮助大...
  • ye563413712
  • ye563413712
  • 2017年05月09日 14:37
  • 118

配置项、基线以及软件配置控制委员会

配置项: 软件配置项是项目定义其受控于软件配置管理的项。一个软件配置项是一个特定的、可文档化的工作产品集,这些工作产品是在生存期中产生或者使用的。 Pressman给出的软件配置项定义:软...
  • liuchuo
  • liuchuo
  • 2016年11月23日 17:26
  • 744

什么是软件配置项?

配置项(Configuration Item)凡是纳入配置管理范畴的工作成果都是配置项(CI);一个纯软件的CIs通常也称为软件配置项(CSCIs)。配置项主要有两大类:属于产品组成部分的工作成果;项...
  • stamina88
  • stamina88
  • 2009年08月26日 16:15
  • 6319

Android:使用密码技术安全地保存凭证

Using Cryptography to Store Credentials Safely http://android-developers.blogspot.com/2013/02/using...
  • ultrapro
  • ultrapro
  • 2013年03月19日 09:45
  • 1397
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:安全地保存配置项
举报原因:
原因补充:

(最多只允许输入30个字)