PDA

View Full Version : [C#/C++] File di configurazione protetto


mcaisco
17-12-2008, 08:30
Salve,

sto sviluppando una mia applicazione e vorrei creare un file di configurazione che contenga un po' di tutto. Ho giò spulciato il namespace .Net relativo ai file di configurazione. Tuttavia, anche se è certamente un namespace completissimo e ben fatto, produce inevitabilmente dei file xml di configurazione in output.
Io però in realtà vorrei che i dati di configurazione siano protetti, sopratutto per evitare che l'utente smanettone si vada a modificare a piacimento questi dati, causando magari malfunzionamenti imprevisti all'applicazione. Dunque un file xml è sicuramente troppo facilmente editabile...
Ho pensato in realtà a due soluzioni.
1) Creare una classe (programmo in C#/VC++) per la configurazione che includa tutto ciò che mi serve e poi la serializzo in binario. In questo caso è necessario fornire un'applicazione apposita che conosca come è fatta la classe e possa quindi deserializzarla per poterla gestire... una sorta di Configuration Manager diciamo.
2) Criptare il file di configurazione xml prodotto con il namspace Configuration di .Net. Anche in questo caso comunque serve una seconda applicazione che permetta di decriptare il file per poterlo editare, magari anche semplicemente producendo il file xml in chiaro (e poi ovviamente dovrebbe ridecriptarlo). Ovviamente questo implica l'uso di un algoritmo di crittografia e almeno una chiave segreta sicura.

Che ne pensate? Avete suggerimenti o altre idee?

Grazie

gugoXX
17-12-2008, 08:58
Sotto C# c'e' un approccio standard.
Aggiungi al progetto (ad ogni progetto eventualmente) un file di configurazione. Sara' app.config per le DLL e le Winform, e web.config per le applicazioni web (siti o web services), che lo aggiungeranno gia' di default.
Il 2 file sono pressoche' analoghi.
E' diviso in diverse sezioni, alcune sempre presenti, altre opzionali aggiunte a seconda delle componenti del progetto.
C'e' una sezione per le ConnectionString verso database
Ce n'e' una per mantenere tutte le informazioni relative alle connessioni verso WebService
C'e' n'e' una in cui e' possibile inserire dati custom sotto forma di chiave-valore, che e' quella che penso a te interessi (appSettings)
Per accedere al file di configurazione e ai dati delle varie sezioni si usa la classe ConfigurationManager.

Questo e' l'approccio standard che ti consiglio di usare.

C'e' poi un'estensione consigliata da varie sorgenti (almeno CodeProject e ComputerProgramming), che prevede la costruzione di un semplice ProgrammaBatch, lanciato in fase di precompilazione, che si occupi di leggere tutti i file .config di tutte le directory della soluzione, che interpreti la sola sezione appSettings contenente i dati custom e che crei (tipicamente sovascriva) al volo un file .cs contenente una partial static class, con una variabile per ciascuna delle entry chiave-valore.
In questo modo potrai accedere alle singole chiavi in modo sicuro, senza preoccuparti se la singola chiave esista oppure no, perche' se non dovesse esistere il programma nemmeno compilera'
E' molto comodo per evitare errori a runtime. Da pagare c'e' il fatto che quando cambi una entry del file di configurazione dovrai ricompilare l'applicazione. A seconda che questo possa andarti bene oppure no, ti consiglio di usare o meno anche questa estensione.

Per il tuo problema specifico mi sentirei di consigliarti quest'ultima estensione.
In questo modo dal tuo lato di sviluppatore continuerai a manutenere una soluzione classica con il file di configurazione standard.
I cui dati verranno pero' compilati all'interno dell'applicazione, e non saranno quindi cambiabili da nessuno, nemmeno dall'utente

Ah, se non sbaglio il file di configurazione standard prevede gia' una sezione per contenere dati cifrati, con diversi algoritmi. (ES: RsaProtectedConfigurationProvider)
Tale sezione sarebbe automaticamente trasparente alla tua applicazione.
Tu continueresti ad usare dati in chiaro nel tuo .config file, e tali dati verrebbero pero' cifrati nella costruzione del file di configurazione finale che ti ritorveresti una volta compilato, che sara' quello distribuito agli utenti.
( <EncryptedData><CipherData><CipherValue>)
Mai usato.

RaouL_BennetH
17-12-2008, 10:08
Ah, se non sbaglio il file di configurazione standard prevede gia' una sezione per contenere dati cifrati, con diversi algoritmi. (ES: RsaProtectedConfigurationProvider)
Tale sezione sarebbe automaticamente trasparente alla tua applicazione.
Tu continueresti ad usare dati in chiaro nel tuo .config file, e tali dati verrebbero pero' cifrati nella costruzione del file di configurazione finale che ti ritorveresti una volta compilato, che sara' quello distribuito agli utenti.
( <EncryptedData><CipherData><CipherValue>)
Mai usato.

Questo approccio l'ho provato io per studio qualche tempo fa:

questo è il codice che trovai di esempio e che, con qualche lieve modifica per lo scopo ho utilizzato:


using System;
using System.Configuration;

namespace TestPSql
{
public class ProtectorApp
{
public void CryptAppConfig()
{
string exePath = System.IO.Path.Combine(Environment.CurrentDirectory, "TestPsql.exe");

System.Configuration.Configuration config =
ConfigurationManager.OpenExeConfiguration(
exePath);

// Define the Rsa provider name.
string provider =
"RsaProtectedConfigurationProvider";

// Get the section to protect.
ConfigurationSection connStrings =
config.ConnectionStrings;

if (connStrings != null)
{
if (!connStrings.SectionInformation.IsProtected)
{
if (!connStrings.ElementInformation.IsLocked)
{
// Protect the section.
connStrings.SectionInformation.ProtectSection(provider);

connStrings.SectionInformation.ForceSave = true;
config.Save(ConfigurationSaveMode.Full);

System.Windows.Forms.MessageBox.Show("Section {0} is now protected by {1}" +
connStrings.SectionInformation.Name,
connStrings.SectionInformation.ProtectionProvider.Name);

}
else
System.Windows.Forms.MessageBox.Show(
"Can't protect, section {0} is locked" +
connStrings.SectionInformation.Name);
}
else
System.Windows.Forms.MessageBox.Show(
"Section {0} is already protected by {1}" +
connStrings.SectionInformation.Name +
connStrings.SectionInformation.ProtectionProvider.Name);

}
else
System.Windows.Forms.MessageBox.Show("Can't get the section {0}" +
connStrings.SectionInformation.Name);


}

}
}


E questo è l'app.config che ne veniva fuori:


?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
</configSections>
<connectionStrings configProtectionProvider="RsaProtectedConfigurationProvider">
<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>AtvvtNBuoQLCejsSeuDzd2mzlayXzc6Qv1BPZr/K9zC/Q2nYumtGjuqXllta1JEmMbnOrHf8Zo4KoXffa5fgUurRzzD+MWhKI+p5HYRqJ/cTgPtVhWEWqw8FobEyLk6AFJC5hmH8tS9FveAN8Cdf8cita64zHUNMLvxBzdLf/9E=</CipherValue>
</CipherData>
</EncryptedKey>
</KeyInfo>
<CipherData>
<CipherValue>n8w/pvln0ro3MVAAMJTss4lrnt/QYNuNhXnKnN30s4mX/TXGOJMVn/e7hN3DLs9iXD0Vmca9KzNRMhQ1Llj/UD0YWo8AyULJFohyX/f6dGAEhUgNKlMXfxlsf2wpNqCjq7rlJ0+1Kv39Pw69HdsWSFu6ZIF7v5brk+kFWU3v7XHJ/OMxjwQ7g4UEiYNRJkRYBSodik5QsxVY4FsUfdDAsoPkWaI1hkRE7AxfFuOxxSPKcMwHaCJ8HZQojUdRrPhfTLCRwtZqHjQCvKkODxHaQTy0l6r+uU4coS7ZSuqz93uoqqmEovntYfBVCLx0lYxBzW+LoSSjnBtglMeIXBm9DQHKieI8kDuQBnuJhn75/V7xYKAycOfwwtzOynnGzApct2gKKcV/81tj5EXdmE5CTaUeBdDP/bd1sul7e/39Mxx5tglcU4cj4R6n6JQ1IdCGC5nDkG4aGMBFrYHqJP9rIUTUJucMCtYgucK6sGB6ltXHIa1bm8y5HbPhcIuXZ2zZqcFLCAxAwFkyLHEQ2QQhInecY9qu+PB2i78pQ6wPgWjg84rhZH9TIgDhYbTCFpWz5wscmcf5t3oFyVj1TwKCxYWdZv4UFvY7fvRyvvATShqPYNHlX73ddF48aqlcSd15ULxNf7FI+HZeUuvpovszF22IYLqyLWm/dNE2HZh5gBtUcpiJMI1YUmJWUaY4tmbd</CipherValue>
</CipherData>
</EncryptedData>
</connectionStrings>
</configuration>

tomminno
17-12-2008, 10:49
Per come ho capito io il tuo problema, l'utilizzo che vuoi fare del file di configurazione, non è quello dei file di configurazione.
L'obiettivo di un file di configurazione è proprio quello di poter essere modificato, ma te non vuoi che questo avvenga.
Potresti usare un file xml embedded, ma che io sappia poi non puoi usare, per accedervi, i metodi della classe ConfigurationManager.
Ma un file embedded non è in definitiva tanto più comodo di una classe con tutte le proprietà che ti servono, in quanto ad ogni modifica delle configurazioni necessita di ricompilazione.

^TiGeRShArK^
17-12-2008, 13:19
Per come ho capito io il tuo problema, l'utilizzo che vuoi fare del file di configurazione, non è quello dei file di configurazione.
L'obiettivo di un file di configurazione è proprio quello di poter essere modificato, ma te non vuoi che questo avvenga.
Potresti usare un file xml embedded, ma che io sappia poi non puoi usare, per accedervi, i metodi della classe ConfigurationManager.
Ma un file embedded non è in definitiva tanto più comodo di una classe con tutte le proprietà che ti servono, in quanto ad ogni modifica delle configurazioni necessita di ricompilazione.

ti quoto..
i file di configurazione devono essere semplicemente modificabili, altrimenti perdono la loro funzione....

mcaisco
17-12-2008, 16:07
Allora, grazie della partecipazione innanzi tutto. Ragioniamo un po'.

Fondamentalmente quello che voglio ottenere è un'applicazione configurabile senza ricompilarla ogni volta. I dati di configurazione possono essere eterogenei, in questo momento io vorrei implementare un sistema di configurazione estendibile e riutilizzabile.
Sono d'accordo che un file di configurazione di per sé debba essere modificabile a mano, ma non è quello che voglio fare. L'utente deve poter modificare alcune cose, ma non tutte, altre possono essere modificabili solo con determinati diritti (è un'applicazione multiutente).

La mia idea è quella di utilizzare un file unico, che però non contenga in chiaro i dati di configurazione proprio perchè l'utente non deve poterli modificare a piacimento o per sbaglio. Quindi ho pensato di creare una classe apposita che rappresenti i dati di configurazione, in cui ad esempio, ogni dato è rappresentato da una proprietà/campo della classe. Poi ovviamente dovrò implementare anche una form che gestisca i dati di configurazione internamente all'applicazione. Questa form è una sorta di Manager che leggerà i dati di configurazione disponibili, visualizzando opportunamente il valore (textBox, comboBox...), e fornendo la possibilità di modificarli in maniera corretta con opportuni metodi. La cosa più semplice con questo approccio è certamente quello di serializzare la classe che rappresenta la configurazione in un file binario. Quindi all'avvio dell'applicazione istanzierei la classe della configurazione che deserializzerebbe il file, caricando in memoria tutti di dati che verrebbero usati dall'applicazione. Quando voglio modificare alcuni dati, attraverso la form Manager descritta sopra, potrei tranquillamente editare i dati di configurazione e l'operazione di salvataggio non farebbe altro che serializzare di nuovo la classe della configurazione e applicare i cambiamenti apportati.
A me pare che questo approccio eviti la necessità di ricompilare ogni volta che voglio modificare qualcosa. Devo solo eseguire l'applicazione e modificare le cose tramite il Manager. O sbaglio?

L'idea di usare il file di configurazione standard di .Net magari cifrando i dati è certamente una via percorribile. Anche in quel caso userei un opportuno Manager per la configurazione, che in questo caso userà i metodi del framework già predefiniti per modifiicare e caricare i dati di configurazione. Anche in questo caso quindi non servirebbe ricompilare tutto ogni volta che voglio modificare le cose. O sbaglio anche qui?

L'unico problema che vedo nell'uso della configurazione standard .Net in xml, è appunto il fatto che xml è un formato testuale. Dunque in ogni caso, anche se i dati di configurazione sono cifrati, l'utente potrebbe comunque tentare di modificarne il contenuto, o anche solo cancellare qualche elemento xml.

Non saprei. Mi sfugge qualcosa nel mio ragionamento? Il file binario eventualmente è effettivamente sicuro? Nel senso, il file binario altro non è che la classe che rappresenta la configurazione, che viene serializzata quando salvo delle modifiche. Questo file binario a me pare molto più difficilmente modificabile che un file xml o ini. Sbaglio?

Grazie mille

!fazz
17-12-2008, 16:38
Allora, grazie della partecipazione innanzi tutto. Ragioniamo un po'.

Fondamentalmente quello che voglio ottenere è un'applicazione configurabile senza ricompilarla ogni volta. I dati di configurazione possono essere eterogenei, in questo momento io vorrei implementare un sistema di configurazione estendibile e riutilizzabile.
Sono d'accordo che un file di configurazione di per sé debba essere modificabile a mano, ma non è quello che voglio fare. L'utente deve poter modificare alcune cose, ma non tutte, altre possono essere modificabili solo con determinati diritti (è un'applicazione multiutente).

La mia idea è quella di utilizzare un file unico, che però non contenga in chiaro i dati di configurazione proprio perchè l'utente non deve poterli modificare a piacimento o per sbaglio. Quindi ho pensato di creare una classe apposita che rappresenti i dati di configurazione, in cui ad esempio, ogni dato è rappresentato da una proprietà/campo della classe. Poi ovviamente dovrò implementare anche una form che gestisca i dati di configurazione internamente all'applicazione. Questa form è una sorta di Manager che leggerà i dati di configurazione disponibili, visualizzando opportunamente il valore (textBox, comboBox...), e fornendo la possibilità di modificarli in maniera corretta con opportuni metodi. La cosa più semplice con questo approccio è certamente quello di serializzare la classe che rappresenta la configurazione in un file binario. Quindi all'avvio dell'applicazione istanzierei la classe della configurazione che deserializzerebbe il file, caricando in memoria tutti di dati che verrebbero usati dall'applicazione. Quando voglio modificare alcuni dati, attraverso la form Manager descritta sopra, potrei tranquillamente editare i dati di configurazione e l'operazione di salvataggio non farebbe altro che serializzare di nuovo la classe della configurazione e applicare i cambiamenti apportati.
A me pare che questo approccio eviti la necessità di ricompilare ogni volta che voglio modificare qualcosa. Devo solo eseguire l'applicazione e modificare le cose tramite il Manager. O sbaglio?

L'idea di usare il file di configurazione standard di .Net magari cifrando i dati è certamente una via percorribile. Anche in quel caso userei un opportuno Manager per la configurazione, che in questo caso userà i metodi del framework già predefiniti per modifiicare e caricare i dati di configurazione. Anche in questo caso quindi non servirebbe ricompilare tutto ogni volta che voglio modificare le cose. O sbaglio anche qui?

L'unico problema che vedo nell'uso della configurazione standard .Net in xml, è appunto il fatto che xml è un formato testuale. Dunque in ogni caso, anche se i dati di configurazione sono cifrati, l'utente potrebbe comunque tentare di modificarne il contenuto, o anche solo cancellare qualche elemento xml.

Non saprei. Mi sfugge qualcosa nel mio ragionamento? Il file binario eventualmente è effettivamente sicuro? Nel senso, il file binario altro non è che la classe che rappresenta la configurazione, che viene serializzata quando salvo delle modifiche. Questo file binario a me pare molto più difficilmente modificabile che un file xml o ini. Sbaglio?

Grazie mille

secondo me ti conviene cifrare il contenuto con una bella chiave e risolvi il problema. se hai paura di cancellazioni al file io calcolerei l'hash e lo salverei su un secondo file