我希望能够检测到关键配置文件何时被更改.
我已经使用Configuration Section Designer来创建一个简单的配置文件,但现在我找不到一种简单的方法来加密结果或为它添加一个值来检查它是否已被更改.
我希望能够阻止未经授权的用户更改配置文件,或者至少知道文件是否已更改.
如果授权用户可以更改配置文件,则高级方法将使用非对称密钥对文件进行签名.只有具有私钥访问权限的授权个人才能生成散列,但应用程序可以仅使用公钥来验证散列(以及文件本身)的合法性.下面是一个快速实现.
此实现需要生成三个文件:
应用程序访问文件(1)和(2).文件(3)是机密的,仅限于授权用户.
基本机制是这样的:
1.生成RSA密钥对
RSA密钥数据可以生成为XML:
(use System.Security.Cryptography)
var csp = new RSACryptoServiceProvider();
string publicXml = csp.ToXmlString(false);
string privateXml = csp.ToXmlString(true);
Run Code Online (Sandbox Code Playgroud)
这将以下列格式生成XML数据.
publicXML:
<RSAKeyValue>
<Modulus>oQKZR9hHrqm1tauCFYpbFlwyRNIHeyc2HCX+5htF/oc1x8Nk8i+itTzwRlgQG1cICO6lX
A+J9/OO2x2b9JILtk2tQow10xJdIsuiBeRwe7wJRdS8+l21F/JPY0eu/xiKQy
ukzEWLjIxGX7UXb9e4ltIxyRUUhk5G/ia1trcxfBc=
</Modulus>
<Exponent>AQAB</Exponent>
</RSAKeyValue>
privateXml:
<RSAKeyValue><Modulus>oQKZR9hHrqm1tauCFYpbFlwyRNIHeyc2HCX+5htF/oc1x8Nk8
i+itTzwRlgQG1cICO6lXA+J9/OO2x2b9JILtk2tQow10xJdIsuiBeRwe7wJRdS8+l21F/JPY0eu/xiKQ
yukzEWLjIxGX7UXb9e4ltIxyRUUhk5G/ia1trcxfBc=</Modulus><Exponent>AQAB</Exponent>
<P>zpFEWa7ave3wHL7pw7pSG0KXDPRwhCzU1Z5/fLoqSrPQzbkRqU+cwDVO/6IId3HdeXE09kVIu9/HBId
vupnY9w==</P><Q>x4pmqkmB7i8g9d3G6RSeZWYde8VOS5/OHUKgM6VrlQhgyrATpxGWAzJAe5eNO2BU
axNO8fZPe+lUSCJgY6TN4Q==</Q><DP>jaNL05ayhDLHRl6dmUiDjg+N1SMyl17KHSON1O8tmoVLchQp
CQf+ukiTP3NSDNy1eNTn9MkzAyeAphlbwf5Fpw==</DP><DQ>HhmUjw9zmBhn4m7H+JTxp94ViHwk6Wd
70hIg1GmZpuuSnkCdVlBizqyf6YTc+x323ggVmo5LQyfZXOBCpgVQQQ==</DQ><InverseQ>iO0CKRGB
2ULS6is/SwonqJw5fBsI9HTzx8rmKGA189dwlLGJSJuQo8uWmrLYhuo22BAqd0lMqxlKCHv6leeGPw==
</InverseQ><D>RSLliJkRJqnO0cRkZjVzqWVLXIvHFJWgwXN7QXlik8mhSTbYqLnVpvcUwU/dErBLTf
KTZLVza9nUdLgBGIKBrkbIqIWixq1fQ3zsEkyB/FQxwhIerTrhHyPzR+i3+5mduqQ7EBTj64u6STUf0y
TXHW2FYlfAinNz+K3iQFFarEE=</D></RSAKeyValue>
Run Code Online (Sandbox Code Playgroud)
私钥字符串应该(通过任何机制)保存到File(3)(私钥).确认文件完整性的应用程序将需要公钥字符串(稍后在步骤3中讨论).
2.签署配置文件
要对配置文件进行签名,您将需要在步骤(1)中生成的私钥Xml字符串.
private byte[] GetFileSha1Hash(string file)
{
using (var fs = new FileStream(
file, FileMode.Open))
{
return new SHA1CryptoServiceProvider().ComputeHash(fs);
}
}
static string GetConfigurationFileSignature(string configfile, string privateXml)
{
var p = new RSACryptoServiceProvider();
p.FromXmlString(privateXml);
byte[] signature = p.SignHash(GetFileSha1Hash(configfile),
CryptoConfig.MapNameToOID("SHA1"));
return Convert.ToBase64String(signature)
}
Run Code Online (Sandbox Code Playgroud)
调用GetConfigurationFileSignature将返回base64编码的字符串.将此字符串保存到File(2)中,应用程序将在该文件中引用它.
3.检查配置文件的完整性
加载配置文件时,应用程序应根据数字签名检查配置文件签名. 公钥应该存储在应用程序中而不是存储在配置文件中 - 否则,攻击者可以简单地用配置文件中的公钥覆盖他/她知道相应私钥对的公钥.
static bool VerifyConfigurationFileSignature(string fileName, string publicXml, string signature)
{
var p = new RSACryptoServiceProvider();
p.FromXmlString(publicXml);
return p.VerifyHash(
GetFileSha1Hash(fileName),
CryptoConfig.MapNameToOID("SHA1"),
Convert.FromBase64String(signature));
}
Run Code Online (Sandbox Code Playgroud)
(注意:您可以使用AppDomain.CurrentDomain.SetupInformation.ConfigurationFile获取当前配置文件的路径.)
当应用程序加载时,它可以VerifyConfigurationFileSignature使用配置文件的路径,公钥XML数据和已知签名进行调用.如果此方法返回false,则表示文件已被篡改; 如果它返回true,则表明该文件是合法的.
最后的笔记
GetFileSha1Hash可以在XML中搜索特定键/值对的更专业的实现,并仅对该数据进行签名,从而允许对配置文件进行其他修改.GetFileSha1Hash,因为在文件中更新散列本身会使先前散列无效.一个专门的实现GetFileSha1Hash可以在生成配置文件哈希时忽略生成的哈希值,从而防止需要单独的配置文件.