安全地保存配置项

 


在作具体的应用的时候,我们通常都会在
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; 
}
 

posted @ 2005-09-01 15:45  风满袖  阅读(1350)  评论(0编辑  收藏  举报