在iPhone操作系统中加密SQLite数据库文件

20

iPhone上的任何SQLite数据库都只是应用程序捆绑的文件。任何人都可以相对简单地提取该文件并查询其中的内容。

您有什么加密文件或在数据库内存储数据的建议吗?

编辑:该应用程序是一款将与其他用户对战的游戏。关于用户的相对实力和弱点的信息将存储在数据库中。我不希望用户能够越狱并修改其声誉/能力等,然后赢得锦标赛/联赛等比赛(注:由于该想法受到保密协议的保护,因此试图进行模糊处理)。

我不需要军事级别的加密,我只是不想以明文形式存储东西。

编辑2:更进一步的说明,我的主要目标是:

  1. 使敏感数据的黑客攻击变得非常困难
  2. 拥有简单的方法发现数据是否已被篡改(使用某种校验和)

任何可以被你的应用程序读取和写入的内容,都可以被有决心的人读取和写入。如果这个应该是一个多人游戏防作弊的话,难道你不应该将这些数据与主游戏代码一起存储在服务器上吗?我说的是像《暗黑破坏神II》封闭的Battle.net模式,以及在《圣域》和其他几款游戏中也存在的模式。 - Ivan Vučica
5
你无法相信客户端。用户可以使用反汇编程序在游戏结束之后但写入数据库之前更改游戏结果。这样,数据库仍然是完全加密和校验过的......但结果已被篡改。 - ilya n.
8个回答

19

无论如何,你都不能相信客户端。如果你的应用程序可以解密数据,那么他们也能做到。要么将数据放在服务器上,要么就不要费力了,因为实际破解数据来提高统计数据的人数非常少,并且他们可能应该得到奖励!

在数据库中放置一个字符串,写着“请勿作弊”。


12

这里至少有两种更容易的方法(互补)可避免加密值或内存数据库:

#1 - ipa破解检测

避免加密数据库和/或内容时可能出现的技术上的麻烦(和法律上的问题),只需确定应用程序是否被盗版并禁用游戏的网络/得分/排名方面。有关详细信息,请参见以下内容:

http://thwart-ipa-cracks.blogspot.com/2008/11/detection.html

#2 - 数据完整性验证

另一种方法是在保存数据时(和初始sqlite数据库中)为每行的重要列存储一个HMAC/盐散列。当加载每行时,对数据进行验证HMAC/散列,并且如果验证失败,则采取相应措施。

这两种方法都不需要填写苹果/美国政府要求的加密出口表格。

得分提交

不要忘记,您需要对实际得分提交进行类似的操作,以防止来自其他来源而不是您的应用程序的值。您可以在cocos2d-iphone和cocoslive框架中看到这种实现: http://code.google.com/p/cocos2d-iphone/http://code.google.com/p/cocoslive/

回复评论

这里没有解决方案可以100%防止数据篡改。如果这是一个要求,则客户端必须是只读的,并且所有状态和逻辑都必须在受信任的服务器上计算。根据应用程序的不同,可能需要在客户端上使用额外的反作弊机制。

有许多关于开发大型多人在线游戏的书籍讨论了这些问题。

在代码中具有已知密钥的哈希很可能是一个合理的方法(至少,在考虑通常存在于App Store上的应用程序类型时)。


11

就像Kendall所说的那样,将密钥存储在设备上基本上是在寻求被破解。然而,有些人有他们使用设备上的密钥对数据进行混淆的原因。如果你决定这样做,你可以考虑在实现时使用SQLCipher。它是SQLite的一个构建版本,可以对整个数据库进行透明的页面级加密。在Mobile Orchard上有一个教程介绍如何在iPhone应用程序中使用它。


5
你认为普通用户会做这件事情的可能性有多大?我猜你是通过应用商店进行的,这意味着在进入用户设备之前,一切都已经被签名/加密。他们必须越狱他们的设备才能访问你的数据库。
你存储了什么类型的数据,需要加密吗?如果包含用户输入的密码,则不需要加密它们;用户不需要找回自己的密码。如果它是通用的二进制大对象数据,你只想让用户通过应用程序访问它,那么可以简单地使用安全 API存储加密的二进制大对象。
如果你想保护整个数据库,那么仍然需要使用安全 API,但是针对整个文件,必要时解密文件才能打开它。问题在于,如果应用程序没有清理就关闭了,你将得到一个未加密的文件。
你可能想看一下内存驻留数据库或临时数据库,可以使用模板数据或硬编码程序中的架构来创建(请参考sqlite3_open的文档)。 可以对数据进行解密,插入到临时数据库中,然后删除解密数据库。 关闭连接时请按相反的方向执行。 编辑: 你可以自己设计加密方案,只需使用简单的安全系统通过XOR操作将数据与应用程序中存储的值结合,并在其他位置存储哈希以确保其不会更改,等等。

3
如果您自己加密应用程序,您需要在应用商店上传调查问卷中回答“是”,并澄清符合出口限制的规定。 - Remus Rusanu
此外,如果您加密了数据库,提交应用程序到应用商店时可能需要在iTunes Connect上填写加密信息......我听说这实际上非常不容易。 - Ben Gotow

3

SQLCipher:

根据我的经验,SQLCipher是加密数据库的最佳选择。

一旦设置了密钥(“PRAGMA key”),SQLCipher将自动加密数据库中的所有数据!请注意,如果您没有设置密钥,则SQLCipher将与标准SQLite数据库完全相同。

调用sqlite3_key或“PRAGMA key”应在打开数据库后的第一操作中发生。在大多数情况下,SQLCipher使用PBKDF2,即盐和迭代的密钥派生函数,以获取加密密钥。或者,应用程序可以告诉SQLCipher在blob符号中使用特定的二进制密钥(请注意,SQLCipher需要确切的256位密钥材料),即

enter image description here

参考:

http://sqlcipher.net/ios-tutorial

我希望有人能节省时间来研究这个问题。


2
忽略哲学和出口问题,我建议您最好直接加密表中的数据。
您需要在代码中混淆解密密钥。通常,这意味着将它们分成几部分,并使用十六进制编码字符串并使用函数将密钥的各个部分组装在一起。
对于算法,我建议使用您所使用语言的可信AES实现。也许对于C#来说可以使用这个:

http://msdn.microsoft.com/en-us/magazine/cc164055.aspx

最后,您需要注意这种方法的局限性。即,解密密钥是一个薄弱环节,在运行时将以明文形式在内存中可用。(至少)必须如此才能使用它。您的加密方案的实现是另一个弱点——任何缺陷都是您代码的缺陷。正如其他一些人指出的那样,您的客户端-服务器通信也存在问题。
您应该记住,您的可执行文件可以在十六进制编辑器中进行检查,其中明文字符串将从编译代码的随机垃圾中跳出。而且许多语言(例如C#)可以反向编译,只有注释会丢失。
尽管如此,加密数据仍然会提高作弊门槛。这取决于您的小心程度;但即使如此,一个决心坚定的对手仍然会破解您的加密并作弊。此外,如果您的游戏很受欢迎,他们可能会编写工具来轻松完成这项任务,这时您就会面临一场军备竞赛的情况。
关于校验和值,您可以基于一行中的数值之和计算校验和,假设您的数据库中有足够的数字值可供使用。或者,对于一组布尔值,您可以将它们存储在一个 varbinary 字段中,并使用按位异或运算符 ^ 进行比较--您应该最终得到 0。
例如,
对于数字列,
2|3|5|7| 带有校验和列 | 17 |
对于布尔值,
0|1|0|1| 带有校验和列 | 0101 |
如果这样做,您甚至可以在末尾添加一个汇总行来总结您的校验和。但是,如果您不断添加新记录,这可能会有问题。您还可以将字符串转换为其 ANSI/UNICODE 组件并将其相加。
然后当您想要检查校验和时,只需执行如下所示的 select 命令:
Select * 
FROM OrigTable 
right outer join 
(select pk, (col1 + col2 + col3) as OnTheFlyChecksum, PreComputedChecksum from OrigTable) OT on OrigTable.pk = OT.pk
where OT.OnTheFlyChecksum = OT.PreComputedChecksum

海报作者担心用户篡改分数/个人资料数据。虽然加密可以解决这个问题,但保护数据并不是必要的。它增加了法律开销,并阻碍了使用SQL来排序分数、查找排名前列、过滤结果等应用程序。也许我没有正确阅读,但我不明白你的校验和实现如何提供数据完整性检查。至少必须有一个仅应用程序(和服务器)知道的秘密用于计算“校验和”(请参见上面关于盐散列的帖子)。同样,得分提交需要相同的处理方式。 - Bradley Dwyer
1
举个例子,如果你看一下验证日志文件未被篡改的算法,日志的内容是明文的。每个日志条目都包含一些哈希值,可以用于验证日志的内容(其中某些不在日志条目中的秘密用于哈希计算)。除此之外,你还需要将先前的日志条目输入到哈希计算中,以便验证整个链。Git(分布式版本控制系统)使用类似的机制。它不会加密你所控制的文件,但它会基于它们的内容维护一系列哈希值链。 - Bradley Dwyer
校验和仅提供了一种简单的低开销方法来检查值是否已更改。例如,假设col1 = 3 col2 = 3和col3 = 3产生校验和为9;现在玩家“作弊”并将col2的值更改为4,从而产生校验和为10,这与先前计算的总和不匹配。该方法也具有一些严重的限制,并且主要依赖于混淆。但是,发布者正在寻求一种简单的方法来验证更改。基本上,我认为这是一种易于实现、低成本的解决方案,可以提高欲成为作弊者的门槛。 - Cynthia

1

将所有锦标赛结果同步到参赛的所有iPhone中似乎是最简单的。您可以在每场比赛之前这样做:如果两部手机的数据库相互矛盾,就会显示警告。

如果用户A篡改了与用户B的比赛结果,则此结果将传播,直到B最终看到它,并提示A的数据与他的手机不匹配。然后他可以去向A解释他的行为不正确,就像在现实生活中有人作弊一样。

计算最终锦标赛结果时,请显示警告并公布姓名,并取消所有具有矛盾结果的游戏。这将消除作弊的动机。

如前所述,加密无法解决问题,因为您不能信任客户端。即使普通人无法使用反汇编器,只需要一个积极的人,您拥有的任何加密都将被破解。


-5

然而,如果您在Windows平台上,您也可以选择SQLiteEncrypt来满足您的需求。SQLiteEncrypt扩展了sqlite加密支持,但您可以将其视为原始的sqlite3 c库。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接