web-dev-qa-db-fra.com

Rendre le fichier .txt illisible / non modifiable

J'ai un programme qui enregistre un petit fichier .txt avec un meilleur score:

 // 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 rendre le fichier illisible/non modifiable ou le crypter.

Je pensais que je pouvais enregistrer les données dans un fichier de ressources, mais puis-je écrire dans un fichier de ressources? Ou enregistrez-le au format .dll, chiffrez/déchiffrez-le ou recherchez une somme/hachage MD5.

36
Daniel Kng

Vous ne pouvez pas empêcher l'utilisateur de modifier le fichier. C'est leur ordinateur, ils peuvent donc faire ce qu'ils veulent (c'est pourquoi tout le problème des DRM est… difficile).

Puisque vous avez dit que vous utilisiez le fichier pour enregistrer un score élevé, vous avez deux alternatives. Notez que, comme indiqué précédemment, aucune méthode n'empêchera un attaquant vraiment déterminé de falsifier la valeur: puisque votre application s'exécute sur l'ordinateur de l'utilisateur, il peut simplement la décompiler, regardez comment vous protégez la valeur (accédez à n'importe quel secret utilisé dans le processus) et agir en conséquence. Mais si vous êtes prêt à décompiler une application, découvrez le schéma de protection utilisé et trouvez un script/patch pour le contourner uniquement pour changer un nombre que vous seul pouvez voir, eh bien, allez-y?

obscurcir le conten

Cela empêchera l'utilisateur de modifier le fichier directement, mais cela ne les arrêtera pas dès que l'algorithme d'obscurcissement 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.

Signez le conten

Cela n'empêchera pas l'utilisateur de modifier le fichier ou de voir son contenu (mais peu importe, un score élevé n'est pas secret) mais vous pourrez détecter si l'utilisateur l'a falsifié.

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 nouveau calculé. Votre clé doit être gardée secrète.

Crypter le conten

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

Veuillez prendre l'exemple suivant avec un grain de sel et passer le temps nécessaire pour comprendre ce que tout fait avant de le mettre en œuvre (oui, vous l'utiliserez pour une raison triviale, mais à l'avenir vous - ou quelqu'un d'autre - peut-être pas). Portez une attention particulière à la façon dont vous générez l'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();
                }
            }
        }
    }
}
59
Albireo

Comme vous semblez rechercher une sécurité relativement faible, je recommanderais en fait de faire une somme de contrôle. Quelques pseudo-codes:

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

Si le score était de 100, cela deviendrait

100 | a6b6b0a8e56e42d8dac51a4812def434

Pour vous assurer que l'utilisateur n'a pas tempéré avec le fichier, vous pouvez ensuite 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]);
}

Maintenant, bien sûr, dès que quelqu'un connaît votre clé, il peut jouer avec tout ce qu'il veut, mais je considère que cela dépasse la portée de cette question. Le même risque s'applique à tout mécanisme de chiffrement/déchiffrement.

L'un des problèmes, comme mentionné dans les commentaires ci-dessous, est qu'une fois que quelqu'un a compris votre clé (via le forçage brutal), il pourrait la partager et tout le monde pourra modifier très facilement ses fichiers. Un moyen 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é a traversé md5.

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

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

12

Votre meilleur pari est probablement de sécuriser l'intégralité du fichier à l'aide de la sécurité NT standard et de modifier par programme la liste de contrôle d'accès pour protéger l'ensemble du fichier contre toute modification par des utilisateurs indésirables (à l'exception de celui qui usurpe l'identité de votre propre application, bien sûr).

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

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

Dites à vos utilisateurs qu'une fois qu'ils ont modifié manuellement l'intégralité du fichier texte, ils ont perdu votre support. À la fin de la journée, si vous stockez ces données, c'est parce qu'elles sont requises par votre application. Le corrompre ou effectuer la tâche risquée de le modifier manuellement peut faire en sorte que votre application génère 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 MD5 ou SHA hachage et stocker dans un fichier séparé, et une fois que vous voulez le lire ou l'écrire à nouveau, vous allez vérifier que le fichier entier produit le même hachage avant de réécrire dessus.

De cette façon, l'utilisateur peut toujours modifier votre fichier manuellement, mais vous saurez quand ce comportement inattend a été effectué par l'utilisateur (à moins que l'utilisateur ne calcule également le hachage manuellement chaque fois que le fichier est modifié ... ).

9
Matías Fidemraizer

Quelque chose que je n'ai pas encore vu mentionné est le stockage du meilleur score sur un tableau de classement en ligne. Évidemment, cette solution nécessite beaucoup plus de développement, mais comme vous parlez d'un jeu, vous pourriez probablement faire appel à un fournisseur tiers comme Steam, Origin, Uplay, ... Cela a l'avantage supplémentaire de classer les leaders non seulement pour votre machine.

6
Nzall

Vous ne pouvez pas enregistrer de données dans une DLL, et le fichier de ressources et le fichier txt sont modifiables. Il semble que le cryptage soit le seul moyen pour vous. Vous pouvez crypter la chaîne avant de l'enregistrer dans un fichier txt. Jetez un oeil à ce fil: Crypter et décrypter une chaîne

5
edgar.bjorntvedt

Solution simple:
.
ne autre solution:
Écrire les données dans une base de données SQLite?

2
Eugene Krapivin

Vous pouvez le sérialiser et le désérialiser avec le cryptage avec CryptoStream :

Sérialiser le fichier:

  • Créer et ouvrir FileStream en mode écriture
  • Créez Cryptostream et passez votre filestream
  • Écrire du contenu dans Cryptostream (crypter)

Désérialiser le fichier:

  • Créer et ouvrir FileStream en mode lecture
  • Créez Cryptostream et passez votre filestream
  • Lire depuis Cryptostream (décrypter)

Vous pouvez trouver des exemples et plus d'informations ici:

msdn.Microsoft.com/en-us/library/system.security.cryptography.cryptostream.aspx

http://www.codeproject.com/Articles/6465/Using-CryptoStream-in-C

Exemple :

byte[] key = { 1, 2, 3, 4, 5, 6, 7, 8 }; // Where to store these keys is the tricky part, 
byte[] iv = { 1, 2, 3, 4, 5, 6, 7, 8 };
string path = @"C:\path\to.file";

DESCryptoServiceProvider des = new DESCryptoServiceProvider();

// Encryption and serialization
using (var fStream = new FileStream(path, FileMode.Create, FileAccess.Write))
using (var cryptoStream = new CryptoStream(fStream , des.CreateEncryptor(key, iv), CryptoStreamMode.Write))
{
    BinaryFormatter serializer = new BinaryFormatter();

    // This is where you serialize your data
    serializer.Serialize(cryptoStream, yourData);
}



// Decryption
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read))
using (var cryptoStream = new CryptoStream(fs, des.CreateDecryptor(key, iv), CryptoStreamMode.Read))
{
    BinaryFormatter serializer = new BinaryFormatter();

    // Deserialize your data from file
    yourDataType yourData = (yourDataType)serializer.Deserialize(cryptoStream);
}
2
Fabjan

Vous ne pouvez pas écrire dans Ressources , plus d'informations existent dans cette réponse

La raison pour laquelle vous ne pouvez pas modifier une chaîne de ressource au moment de l'exécution est que la ressource est compilée dans votre exécutable. Si vous inversez l'ingénierie du fichier * .exe ou * .dll compilé, vous pouvez réellement voir votre chaîne dans le code. Modifier un fichier exécutable déjà compilé n'est jamais une bonne idée (sauf si vous essayez de le pirater), mais lorsque vous essayez de le faire à partir du code des exécutables, c'est tout simplement impossible, car le fichier est verrouillé pendant l'exécution.

  • Vous pouvez ajouter Lecture seule ou Attributs masqués à vos fichiers en utilisant - File.SetAttributes , mais l'utilisateur peut toujours supprimer les attributs des fenêtres et modifier le fichier.

Un exemple:

File.SetAttributes(path, File.GetAttributes(path) | FileAttributes.Hidden);
  • Une autre façon que je pourrais suggérer est d'enregistrer les données dans un fichier avec des extensions étranges afin que l'utilisateur ne puisse pas le considérer comme un fichier modifiable ou important. quelque chose comme ghf.ytr ( Je ne peux pas penser à quelque chose de plus bizarre en ce moment! )
  • Je suggère également de créer un fichier texte avec .dll extension et l'enregistrer dans l'un des dossiers Windows comme system32. De cette façon, l'utilisateur aura beaucoup de mal à essayer de savoir où vont les informations de score!
1
Alex Jolig

Vous pouvez nommer votre fichier comme quelque chose qui ne suggère pas qu'il contient une table de score (par exemple YourApp.dat) et crypter le contenu.

La réponse acceptée ici contient le code de cryptage et de décryptage du texte.

Mise à jour
Je suggère également d'utiliser un Guid comme mot de passe pour le chiffrement.

1
Dmitri Trofimov

Voici un code pour rendre un fichier texte non modifiable. de la même manière que vous utilisez cette technique pour la rendre illisible, etc.

string pathfile = @"C:\Users\Public\Documents\Filepath.txt";

if (File.Exists(pathfile))
{
    File.Delete(pathfile);
}
if (!File.Exists(pathfile))
{
    using (FileStream fs = File.Create(pathfile))
    {
        Byte[] info = new UTF8Encoding(true).GetBytes("your text to be written to the file place here");

        FileSecurity fsec = File.GetAccessControl(pathfile);
        fsec.AddAccessRule(new FileSystemAccessRule("Everyone",
        FileSystemRights.WriteData, AccessControlType.Deny));
        File.SetAccessControl(pathfile, fsec);
    }
}
0
Priyabrata biswal