Secure config, czyli zabezpieczenie pliku web.config v2
Tweet
wtorek, 8 marzec 2011
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: wygląda tak: a plik ‘connectionStrings.config’ tak: 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. 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:
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:
Do eksportu i importu klucza służą następujące komendy (więcej szczegółów tutaj):
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:
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.
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: wygląda tak: a plik ‘connectionStrings.config’ tak: 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. 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:
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:
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.


Twitter