当前位置:  开发笔记 > 编程语言 > 正文

使.txt文件不可读/不可编辑

如何解决《使.txt文件不可读/不可编辑》经验,为你挑选了5个好方法。

我有一个程序可以保存一个带有高分的.txt文件:

 // 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);

问题是用户可以使用texteditor尽可能简单地编辑文件.所以我想让文件不可读/不可编辑或加密它.

我的想法是我可以将数据保存在资源文件中,但是我可以在资源文件中写入吗?或者将其保存为.dll,加密/解密或查找MD5-sum/hash.



1> Albireo..:

您无法阻止用户修改文件.这是他们的计算机,所以他们可以做任何他们想做的事(这就是为什么整个DRM问题......很难).

既然你说你正在使用该文件来保存高分,那么你有几个选择.请注意,如前所述,没有任何方法可以阻止真正确定的攻击者篡改该值:由于您的应用程序在用户计算机上运行,​​他可以简单地对其进行反编译,看看您是如何保护该值的(获取对任何机密的访问权限)在过程中使用)并采取相应行动.但是如果你愿意反编译一个应用程序,找出所使用的保护方案,并提出一个脚本/补丁来绕过它只是为了改变一个只有你能看到的数字,好吧,去吧?

混淆内容

这将阻止用户直接编辑文件,但只要知道混淆算法就不会停止它们.

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

将密文保存到文件中,并在读取文件时反转该过程.

签署内容

这不会阻止用户编辑文件或查看其内容(但你不在乎,高分并不是秘密),但你将能够检测用户是否篡改了它.

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);
}

将有效负载和散列保存在文件中,然后在读取文件时检查保存的散列是否与新计算的散列匹配.你的钥匙必须保密.

加密内容

利用.NET的加密库在保存内容之前加密内容,并在读取文件时对其进行解密.

请在下面的例子中加入一些盐,并在实施之前花些时间来理解所有事情(是的,你将使用它是为了一个微不足道的原因,但未来你 - 或其他人 - 可能不会).特别注意如何生成IV和密钥.

// 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();
                }
            }
        }
    }
}


请不要使用"密文"来描述`ToBase64String`的输出.密文是*encryption*的输出,而Base 64编码不是.
@Albireo"编码文本"更好,因为它正是它的本质.
当然,当任何人只能提取你的密钥并签名/加密他们自己的文件版本时,任何这种签名/加密的东西都不会救你.
@ njzk2 OP不需要安全性(如他的评论中所述).他只想快速阻止用户调整自己的分数.序列化数据是防止99%用户这样做的好方法.即使是高级用户也必须非常关心如何去反序列化这些数据(因为他们无法访问数据源)......所以它让大多数玩家都无法接触到它.并且,如果有人非常关心如何全面解决这个问题,那么任何安全计划都不会阻止他们.这是他们的PC,他们可以做他们想要的.
好的好的!*littleunplainertext*更好吗?

2> Daniël van d..:

由于你似乎寻找相对较低的安全性,我实际上建议你去校验和.一些伪代码:

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

如果分数为100,则会变为

100 | a6b6b0a8e56e42d8dac51a4812def434

为了确保用户没有使用该文件,您可以使用:

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

当然,当有人知道你的钥匙时,他们可以随心所欲地解决这个问题,但我认为这超出了这个问题的范围.同样的风险适用于任何加密/解密机制.

正如下面的评论中所提到的,其中一个问题是,一旦有人找出你的密钥(通过暴力破解),他们就可以分享它,每个人都可以非常轻松地更改他们的文件.解决此问题的方法是在密钥中添加特定于计算机的内容.例如,登录用户的名称是通过md5运行的.

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

这将阻止密钥"简单地共享".



3> Matías Fidem..:

可能你最好的选择是使用标准NT安全保护整个文件,并以编程方式更改访问控制列表,以保护整个文件不被不需要的用户编辑(当然,除了假冒你自己的应用程序之外).

密码学在这里无法提供帮助,因为文件仍然可以使用常规文本编辑器进行编辑(例如notepad),最终用户可以仅添加额外的字符(或者删除一个字符)来破坏文件.

还有一种不涉及编程工作的替代方法......

告诉您的用户,一旦他们手动编辑了整个文本文件,他们就会失去支持.在一天结束时,如果您存储此数据是因为您的应用程序需要它.破坏它或执行手动编辑它的风险任务可能会使您的应用程序产生错误.

另一种涉及编程工作的替代方法......

每当您从应用程序更改文件时,您都可以计算MD5或SHA哈希并存储在单独的文件中,一旦您想要再次读取或写入,您将检查整个文件是否产生相同的哈希值再写一遍.

这样,用户仍然可以手动编辑您的文件,但您将知道用户何时完成此意外行为(除非用户还在文件更改时手动计算哈希值...).



4> Nzall..:

我还没有看到的一件事是将高分存储在在线排行榜上.显然这个解决方案需要更多的开发,但是既然你在谈论游戏,你可能会使用像Steam,Origin,Uplay这样的第三方提供商......这有一个额外的优势,即排行榜不仅仅是为了你的机器.



5> 小智..:

您无法在dll中保存数据,并且Resource文件和txt文件都是可编辑的.听起来加密是唯一的方式.您可以在将字符串保存到txt文件之前对其进行加密.看看这个帖子: 加密和解密一个字符串

推荐阅读
kikokikolove
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有