配置文件上的篡改检测

本文关键字:检测 配置文件 | 更新日期: 2023-09-27 18:20:58

我希望能够检测关键配置文件何时更改。

我使用配置节设计器创建了一个简单的配置文件,但现在我找不到一种简单的方法来加密结果或向其添加值以检查它是否已更改。

我希望能够防止未经授权的用户更改配置文件,或者至少知道该文件是否已更改。

配置文件上的篡改检测

如果授权用户可以更改配置文件,一种高级方法是使用非对称密钥对文件进行签名。只有有权访问私钥的授权人员才能生成哈希,但应用程序只能用公钥验证哈希的合法性(从而验证文件本身)。下面是一个快速实现。

此实现需要生成三个文件:

  1. 要签名的配置文件
  2. 包含配置文件哈希的应用程序可访问的文件
  3. 包含私钥参数的专用配置文件

文件(1)和(2)由应用程序访问。文件(3)是机密文件,仅限授权用户使用。

基本机制是:

  1. 生成RSA密钥对,并保存公钥和私钥信息。私钥信息保存到文件(3)中,公钥信息合并到应用程序中。此步骤只执行一次
  2. 无论何时更改配置文件,都会使用文件(3)对文件的SHA1哈希进行签名。散列被保存到文件(2)中
  3. 每当程序加载配置文件时,它都会生成配置文件哈希,并使用公钥来验证签名。如果签名匹配,则继续;如果它们不匹配,就会抛出一个异常

1.生成RSA密钥对

RSA密钥数据可以生成XML:

(use System.Security.Cryptography)
var csp = new RSACryptoServiceProvider();
string publicXml = csp.ToXmlString(false);
string privateXml = csp.ToXmlString(true);

这将生成以下格式的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>

私钥字符串应保存(通过任何机制)到文件(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)
    }

调用GetConfigurationFileSignature将返回一个base64编码的字符串。将此字符串保存到文件(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));
    }

(注意:您可以使用AppDomain.CurrentDomain.SetupInformation.ConfigurationFile来获取当前配置文件的路径。)

当应用程序加载时,它可以使用配置文件的路径、公钥XML数据和已知签名来调用VerifyConfigurationFileSignature。如果此方法返回false,则表示文件已被篡改;如果返回true,则表明该文件是合法的。

最终票据

  1. 密码学只确保生成的数字签名是用私钥生成的。攻击者仍然可以覆盖应用程序的验证逻辑来读取恶意配置数据
  2. 对配置文件的任何更改(包括添加注释、空格等)都将导致哈希无效。GetFileSha1Hash的更专业的实现可能会在XML中搜索特定的键/值对,并仅对该数据进行签名,从而允许对配置文件进行其他修改
  3. GetFileSha1Hash的上述实现中,不可能将哈希本身包含在XML文件中,因为在文件中更新哈希本身会使先前的哈希无效。GetFileSha1Hash的专门实现可以在生成配置文件哈希时忽略生成的哈希值,从而避免需要单独的配置文件

确定某个东西是否发生了更改的一种常见方法是使用"哈希",例如,您可以使用配置的MD5哈希或其一部分,然后在每次加载时检查该哈希,以确定它是否已更改。