36 votes

Rendre le fichier .txt illisible / non modifiable

J'ai un programme qui enregistre un petit fichier .txt contenant un score élevé :

 // Create a file to write to. 
string createHighscore = _higscore + Environment.NewLine;
File.WriteAllText(path, createText);

// Open the file to read from. 
string createHighscore = File.ReadAllText(path);

Le problème est que l'utilisateur peut éditer le fichier aussi simplement que possible - avec un éditeur de texte. Je veux donc faire en sorte que le fichier illisible / non modifiable ou le crypter .

Je pensais pouvoir sauvegarder les données dans un fichier de ressources, mais puis-je écrire dans un fichier de ressources ? Ou l'enregistrer en tant que .dll, le crypter/décrypter ou rechercher une somme MD5/hash.

59voto

Albireo Points 4690

Vous ne pouvez pas empêcher l'utilisateur de modifier le fichier. C'est son ordinateur, il peut donc faire ce qu'il veut (c'est pourquoi toute la question des DRM est difficile).

Puisque vous avez dit que vous utilisiez le fichier pour sauvegarder un high-score, vous avez plusieurs possibilités. Notez que, comme nous l'avons dit précédemment, aucune méthode n'empêchera un attaquant vraiment déterminé d'altérer la valeur : puisque votre application est exécutée sur l'ordinateur de l'utilisateur, il peut simplement la décompiler, examiner comment vous protégez la valeur (en accédant à tout secret utilisé dans le processus) et agir en conséquence. Mais si vous êtes prêt à décompiler une application, à découvrir le schéma de protection utilisé et à concevoir un script/patch pour le contourner uniquement pour changer un nombre que vous seul pouvez voir, eh bien, allez-y ?

Obfusquer le contenu

Cela empêchera l'utilisateur de modifier directement le fichier, mais ne l'arrêtera pas dès que l'algorithme d'obfuscation sera connu.

var plaintext = Encoding.UTF8.GetBytes("Hello, world.");
var encodedtext = Convert.ToBase64String(plaintext);

Enregistrez le texte chiffré dans le fichier, et inversez le processus lors de la lecture du fichier.

Signer le contenu

Cela n'empêchera pas l'utilisateur de modifier le fichier ou de voir son contenu (mais vous vous en fichez, un high-score n'est pas secret) mais vous pourrez détecter si l'utilisateur l'a modifié.

var key = Encoding.UTF8.GetBytes("My secret key");
using (var algorithm = new HMACSHA512(key))
{
    var payload = Encoding.UTF8.GetBytes("Hello, world.");
    var binaryHash = algorithm.ComputeHash(payload);
    var stringHash = Convert.ToBase64String(binaryHash);
}

Enregistrez à la fois la charge utile et le hachage dans le fichier, puis, lors de la lecture du fichier, vérifiez si le hachage enregistré correspond à un hachage nouvellement calculé. Votre clé doit rester secrète.

Crypter le contenu

Exploitez les bibliothèques cryptographiques de .NET pour crypter le contenu avant de l'enregistrer et le décrypter lors de la lecture du fichier.

Prenez l'exemple suivant avec un grain de sel et prenez le temps de comprendre ce que fait chaque élément avant de le mettre en œuvre (oui, vous l'utiliserez pour une raison triviale, mais à l'avenir, vous - ou quelqu'un d'autre - ne l'utiliserez peut-être pas). Faites particulièrement attention à la façon dont vous générez le IV et la clé.

// The initialization vector MUST be changed every time a plaintext is encrypted.
// The initialization vector MUST NOT be reused a second time.
// The initialization vector CAN be saved along the ciphertext.
// See https://en.wikipedia.org/wiki/Initialization_vector for more information.
var iv = Convert.FromBase64String("9iAwvNddQvAAfLSJb+JG1A==");

// The encryption key CAN be the same for every encryption.
// The encryption key MUST NOT be saved along the ciphertext.
var key = Convert.FromBase64String("UN8/gxM+6fGD7CdAGLhgnrF0S35qQ88p+Sr9k1tzKpM=");

using (var algorithm = new AesManaged())
{
    algorithm.IV = iv;
    algorithm.Key = key;

    byte[] ciphertext;

    using (var memoryStream = new MemoryStream())
    {
        using (var encryptor = algorithm.CreateEncryptor())
        {
            using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
            {
                using (var streamWriter = new StreamWriter(cryptoStream))
                {
                    streamWriter.Write("MySuperSecretHighScore");
                }
            }
        }

        ciphertext = memoryStream.ToArray();
    }

    // Now you can serialize the ciphertext however you like.
    // Do remember to tag along the initialization vector,
    // otherwise you'll never be able to decrypt it.

    // In a real world implementation you should set algorithm.IV,
    // algorithm.Key and ciphertext, since this is an example we're
    // re-using the existing variables.
    using (var memoryStream = new MemoryStream(ciphertext))
    {
        using (var decryptor = algorithm.CreateDecryptor())
        {
            using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
            {
                using (var streamReader = new StreamReader(cryptoStream))
                {
                    // You have your "MySuperSecretHighScore" back.
                    var plaintext = streamReader.ReadToEnd();
                }
            }
        }
    }
}

12voto

Comme vous semblez rechercher une sécurité relativement faible, je vous recommande d'opter pour une somme de contrôle. Un peu de pseudo-code :

string toWrite = score + "|" + md5(score+"myKey") + Environment.NewLine

Si le score était de 100, cela deviendrait

100|a6b6b0a8e56e42d8dac51a4812def434

Pour s'assurer que l'utilisateur n'a pas tempéré avec le fichier, vous pouvez alors utiliser :

string[] split = readString().split("|");
if (split[1] != md5(split[0]+"myKey")){
     alert("No messing with the scores!");
}else{
     alert("Your score is "+split[0]);
}

Bien entendu, dès que quelqu'un connaît votre clé, il peut en faire ce qu'il veut, mais je considère que cela dépasse le cadre de cette question. Le même risque s'applique à tout mécanisme de cryptage/décryptage.

L'un des problèmes, comme mentionné dans les commentaires ci-dessous, est qu'une fois que quelqu'un a découvert votre clé (par forçage brutal), il peut la partager et tout le monde pourra très facilement modifier ses fichiers. Une façon de résoudre ce problème serait d'ajouter quelque chose de spécifique à l'ordinateur à la clé. Par exemple, le nom de l'utilisateur qui s'est connecté, analysé par md5.

string toWrite = score + "|" + md5(score+"myKey"+md5(System.username /**or so**/)) + Environment.NewLine

Cela empêchera la clé d'être "simplement partagée".

9voto

Matías Fidemraizer Points 16842

Le mieux est probablement de sécuriser l'ensemble du fichier à l'aide de la sécurité NT standard et de modifier par programme la liste de contrôle d'accès afin de protéger l'ensemble du fichier contre toute modification par des utilisateurs indésirables (à l'exception de celui qui se fait passer pour votre propre application, bien sûr).

La cryptographie ne peut pas aider ici, car le fichier peut toujours être modifié à l'aide d'un éditeur de texte ordinaire (par exemple, notepad ) et l'utilisateur final peut corrompre le fichier en ajoutant simplement un caractère supplémentaire (ou en en supprimant un aussi).

Il existe une autre approche qui n'implique pas d'effort de programmation...

Dites à vos utilisateurs qu'une fois qu'ils ont édité manuellement l'ensemble du fichier texte, ils ont perdu votre soutien. En fin de compte, si vous stockez ces données, c'est parce qu'elles sont nécessaires à votre application. Si vous les corrompez ou si vous faites la tâche risquée de les modifier manuellement, votre application risque de produire des erreurs.

Une autre approche alternative qui implique un effort de programmation...

Chaque fois que vous modifiez le fichier à partir de votre application, vous pouvez calculer un hachage MD5 ou SHA et le stocker dans un fichier séparé, et lorsque vous voudrez le lire ou l'écrire à nouveau, vous vérifierez que l'ensemble du fichier produit le même hachage avant d'écrire à nouveau dessus.

De cette façon, l'utilisateur peut toujours éditer votre fichier manuellement, mais vous saurez quand cela inattendu a été fait par l'utilisateur (sauf si l'utilisateur calcule aussi manuellement le hachage à chaque fois que le fichier est modifié...).

6voto

Nate Kerkhofs Points 1792

Une chose que je n'ai pas encore vue mentionnée est le stockage du meilleur score sur un tableau de classement en ligne. Cette solution nécessite évidemment beaucoup plus de développement, mais comme il s'agit d'un jeu, vous pourriez probablement utiliser un fournisseur tiers comme Steam, Origin, Uplay, ... Cela présente l'avantage supplémentaire que les tableaux de classement ne sont pas réservés à votre machine.

5voto

Vous ne pouvez pas enregistrer de données dans un fichier DLL, et les fichiers Resource et txt sont modifiables. Il semble que le cryptage soit la seule solution pour vous. Vous pouvez crypter la chaîne avant de l'enregistrer dans un fichier txt. Jetez un coup d'œil à ce fil de discussion : Cryptage et décryptage d'une chaîne de caractères

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X