安全地保存配置项

转载 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; 
}
 

相关文章推荐

PHP+JS密码加密实现HTTP上安全地传输密码

1、理论 在普通HTTP上,一般表单中的密码都是以明文方式传到服务器进行处理的。这无疑给了坏人以可乘之机!这里我们就说说怎么传输密码才是安全的! 与其传输密码本身,到不如传输其加密后的形式。MD5是个...

使用一次性密码解决方案更安全地验证身份

MSDN 杂志 > 主页 > 所有期刊 > 2008 > May >  安全性: 使用一次性密码解决方案更安全地验证身份 安全性 使用一次性密码解决方案更安全地验证身份 Dan Griffin ...

JSON Web Token (JWT) - 在Web应用间安全地传递信息

JSON Web Token (JWT) - 在Web应用间安全地传递信息
  • ztguang
  • ztguang
  • 2016年11月14日 09:33
  • 755

cpp如何快速安全地将文件读入字符串string或字符数组vector<string>的方法

就不多解释了,自己看吧 // ----------------------------------------------------------------------------- // 功...

在WebView中如何让JS与Java安全地互相调用

在现在安卓应用原生开发中,为了追求开发的效率以及移植的便利性,使用WebView作为业务内容展示与交互的主要载体是个不错的折中方案。那么在这种Hybrid(混合式) App中,难免就会遇到页面JS需要...

正确、安全地停止springboot应用

引言 Spring Boot,作为Spring框架对“约定优先于配置(Convention Over Configuration)”理念的最佳实践的产物,它能帮助我们很快捷的创建出独立运行、产品...

REST 中如何安全地处理用户登录问题?

在设计一个 App 与服务端交互的 REST 风格的 API 时,一直不知道如何处理有关用户登录的各种问题,如: 判定用户是否已经登录如何对每一次 api 请求进行验证服务端与客户端通信时确保用...

为什么operator>>(istream&, string&)能够安全地读入长度未知的字符串?

本文首先试验并分析了栈上定长字符数组输入字符的安全性(char buf[6]; scanf("%s", buf);),然后对operator>>(istream&, string&)的实现细节进行分析...

如何安全地存储密码

 无论是开发App还是网站,只要有用户登录环节,就会牵涉到如何存储用户的密码的问题。如果采用的存储密码的技术不够安全,一旦黑客闯入存储密码的数据库,他就能获取用户的密码从而可能给用户带来重大...

基于visual c++之windows核心编程代码分析(55)使用GoogleUrl方便安全地解析URL

我们在进行google搜索的时候,google为了安全起见,经常对于URL通过谷歌的安全过滤,以过滤网络木马,如下图  下面我们来亲自实践,基于VC++来实现使用GoogleUrl方便安全地解析URL...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:安全地保存配置项
举报原因:
原因补充:

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