Secure config, czyli zabezpieczenie pliku web.config v2

Jak ważne i poufne informacje znajdują się w pliku konfiguracyjnym aplikacji (app.config lub web.config), każdy chyba wie. O szyfrowaniu tychże informacji z poziomu konsoli wspominałem tutaj. W tym artykule zaprezentować chciałbym jak szyfrować/deszyfrować sekcje z poziomu kodu. Zapraszam.

W pierwszej kolejności wydzielimy sekcję do oddzielnego pliku (ja działam na sekcji connectionStrings). Jest to praktyka, do której zachęca Microsoft, ponieważ edycja “zewnętrznych” plików nie powoduje restartu aplikacji. I tak też sekcja, która wyglądała następująco:

<connectionStrings>
 	<clear />
  	<add name="myConnection" connectionString="Valid connection string" />
</connectionStrings>

wygląda tak:

<connectionStrings configSource="connectionStrings.config" />

a plik connectionStrings.config tak:

<?xml version="1.0"?>
<connectionStrings>
	<clear />
	<add name="myConnection" connectionString="Valid connection string" />
</connectionStrings>

Następnie definiujemy własnego providera, który odpowiedzialny będzie za szyfrowanie sekcji. Podajemy w nim dwa istotne atrybuty: keyContainerName oraz useMachineContainer. Pierwszy z nich wyznacza nam nazwę klucza RSA. Drugi natomiast decyduje czy klucz znajduje się w kontenerze na poziomie maszyny, czy też na poziome użytkownika (wyjaśnienie różnicy pomiędzy poziomami można znaleźć tutaj). Nasz provider prezentuje się jak poniżej.

<configProtectedData>
    <providers>
      <add name="MyProvider"
           type="System.Configuration.RsaProtectedConfigurationProvider,System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
           keyContainerName="MySampleKey"
           useMachineContainer="true"/>
    </providers>
</configProtectedData>

Jak widać w powyższym przykładzie, wykorzystujemy klucz RSA, który zapewne nie znajduję się na naszej maszynie, a co za tym idzie należy go utworzyć. Służy do tego poniższa komenda uruchamiana z wiersza poleceń Visual Studio:

aspnet_regiis -pc "MySampleKey" -exp

Od tego momentu nasza maszyna zawiera klucz o zadanej nazwie. W tym miejscu warto wspomnieć, iż po zaszyfrowaniu informacji odkodować je będzie można tylko i wyłącznie na maszynie posiadającej podany klucz. Jeśli maszyna nie będzie zawierać klucza otrzymamy poniższy błąd:

Brak klucza RSA

Do eksportu i importu klucza służą następujące komendy (więcej szczegółów tutaj):

aspnet_regiis -px "MySampleKey" keys.xml -pri
aspnet_regiis -pi "MySampleKey" keys.xml

Na koniec pozostaje nam tylko obsługa od strony kodu. Do testu przygotowałem prostą stronkę z trzema przyciskami oraz kontrolką typu Literal. Poniżej kod akcji tychże przycisków:

protected void bDecrypt_Click(object sender, EventArgs e)
{
    var config = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~");
    var section = config.GetSection("connectionStrings") as System.Configuration.ConnectionStringsSection;

    if (section.SectionInformation.IsProtected)
    {
        section.SectionInformation.UnprotectSection();
    }
    config.Save(System.Configuration.ConfigurationSaveMode.Minimal);
}

protected void bEncrypt_Click(object sender, EventArgs e)
{
    var config = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~");
    var section = config.GetSection("connectionStrings") as System.Configuration.ConnectionStringsSection;

    if (!section.SectionInformation.IsProtected)
    {
        section.SectionInformation.ProtectSection("MyProvider");
    }
    config.Save(System.Configuration.ConfigurationSaveMode.Minimal);
}

protected void bLoad_Click(object sender, EventArgs e)
{
    litConnections.Text = string.Empty;
    foreach (ConnectionStringSettings item in ConfigurationManager.ConnectionStrings)
    {
        litConnections.Text += string.Format("{0}: {1} 
", item.Name, item.ConnectionString);
    }
}

Scenariusz moich testów wygląda następująco. Klikam w przycisk pobrania i wypisania na stronie zawartości sekcji connectionStrings. Wpisy pokazują się poprawnie. Następnie kolejno w przycisk szyfrujący i znowu pobierający informacje. Ponownie zawartość wyświetla się poprawnie. Natomiast w momencie, gdy podglądniemy zawartość pliku connectionStrings.config wygląda ona następująco:

<connectionStrings configProtectionProvider="MyProvider">
  <EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element"
    xmlns="http://www.w3.org/2001/04/xmlenc#">
    <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc" />
    <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
      <EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">
        <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" />
        <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
          <KeyName>Rsa Key</KeyName>
        </KeyInfo>
        <CipherData>
          <CipherValue>X2wpUxf/x3TD+EAHO43Zp3I+bb+Bzhnzg47F91VMhksTPy7KFY38MZ06/Cf6LA4cw+TvaF9se5W7NUxtU66pJuZVxzlqBmy/NIQZ0PtQdNvPw5Je5Z3GpsbLvTRjaBhyHzXSH62O8BHVUoJ/220gtZNTIG6xEc1s4gzRp19L+pg=</CipherValue>
        </CipherData>
      </EncryptedKey>
    </KeyInfo>
    <CipherData>
      <CipherValue>FfkYyyj7F+ZKaxVfffKoF6TZPkhckmt8c5adQmUTjo30GpgUpa0dQqU07GTkBOp508E6uo0Lp4QjABOnoz/1ldyYx2KZhh9hDaTBrIEBTcxFoEghkd5b6Pd59ndvwyLLZlvbrQhcY+ew6PS4zJPeAVKzEE5iO/r7kEOP/QSVHF+FeovtGxxQAs73cYAQfcS+</CipherValue>
    </CipherData>
  </EncryptedData>
</connectionStrings>

Jak widać, po zaszyfrowaniu aplikacja sama “w locie” odszyfrowała informacje oraz wyświetliła prawdziwą zawartość sekcji. Tym samym nie musimy się martwić o obsługę odkodowywania informacji podczas próby ich wykorzystania.
Kliknięcie w przycisk odszyfrowania skutkuje powrotem seksji do swojej pierwotnej postaci.

Szyfrowanie newralgicznych informacji aplikacji przed niepowołanym dostępem nie jest trudne ani pracochłonne. Dlatego też chciałbym wszystkich zachęcić do stosowania któregokolwiek z rozwiązań, gdyż mają one na celu zwiększenie bezpieczeństwa naszych jakże wysoce poufnych informacji.

Promuj

Facebook
Twitter
LinkedIn
Google+
http://kurzyniec.pl/artykuly/secure-config/

Leave a Reply

Your email address will not be published. Required fields are marked *