如何使用 Objective-C 安全地存储数据?(Mac/Cocoa 开发)

7
我正在尝试创建我的cocoa应用程序的试用部分。我已经设置好了许可证(包括密钥)等。
但是我想知道如何在一个安全的地方存储例如用户第一次运行程序的时间,以便用户无法轻易找到和/或编辑它。
我已经尝试使用NSUserDefaults standardUserDefaults进行操作,但是用户可以很容易地在Library>Preferences中找到和编辑该数据。

将其存储在应用程序包中可能会对用户绕过它造成轻微困难。这取决于您希望保护有多好。 - David
@Daniel:问题在于用户可能会删除所有默认设置。 - David
@David,你有什么建议吗? - Daniel
@Daniel:我唯一能想到的就是在捆绑包内的某个文件中进行更改,而这种更改并不明显地与“试用”限制有关。它可能只是在二进制资源之一(如图标文件)中更改几个不重要的字节。问题是,对于了解情况的人来说,仍然很容易对所有文件进行二进制比较,并找出如何将其改回...一旦他们做到了这一点,他们就可以将其作为“破解”分发给普通用户使用。 - David
3
不要更改您的应用程序包内的内容。这会破坏代码签名(从而防止您使用安全框架和密钥链的某些功能),并且通常向用户显示某些东西正在篡改您的应用程序,就像恶意软件一样。 - Louis Gerbarg
显示剩余4条评论
6个回答

22

我认为不要过于追求超级安全。我们曾经有一次服务器激活,但完全放弃了它。以下是一些原因:

  • 即使是最“安全”的存储方法也可能被破解
  • 即使是针对小众产品,也可能会开发出破解方法,无论你的方法有多么安全
  • 只有很少数非常昂贵、非常安全的方法。其他所有方法都已经被破解了
  • 这会对公正用户造成不利影响,使他们难以修复引起问题的东西
  • 如果用户确实破解了您的软件或规避了您的安全措施,那么他也很可能从未购买过它
  • 80%的用户甚至不知道什么是首选项文件
  • 95%的用户不考虑删除文件以延长试用期的可能性
  • 重置试用期的简单方法极大地方便了您想给予第二次试用机会的用户的支持,无论出于何种原因
  • 信任用户是一个好的销售点
  • 高级用户倾向于反对过度保护的软件

我相信有一些例外,但极少。我的建议是:不要浪费时间在注册安全上,而是给


1
我同意,不要浪费太多资源来使你的应用程序超级安全。黑客总会找到绕过它的方法。 - Brad G
1
http://www.aquaticmac.com/是一个良好的安全性解决方案。 http://aquaticmac.com/cocoa.php还提供了对NSData的扩展,可以进行加密。如果您想覆盖99%的用户,我建议使用隐藏文件方法,并使用明显的名称,例如“.<myApplicationNameData>”。 - user160917

4
你不能使用文件系统中的文件。任何想要篡改/破解它的人都会聪明到知道如何通过基本的、标准的OSX功能来跟踪文件访问。因此,添加文件是不可行的。不仅如此,创建应用程序卸载后不删除的文件是不好的行为。人们不应该在删除试用应用程序后仍然被消耗资源。
如上所述,在包中胡乱操作也是不好的主意。这留下了三个根本选项。
1)不要太担心。使用使用标准位置和方法的基本过期系统。您仍然可以在存储的数据中使用加密,但要知道这也会被破解。除非您的应用程序非常不受欢迎,否则侵犯版权将发生。
2)使用网络调用并在服务器上进行验证。这需要应用程序始终能够到达您的服务才能运行。总的来说,这不是一个好主意。如果您的服务器关闭怎么办?如果他们离线怎么办?如果您和他们之间的网络问题发生了什么?所有这些情况都会发生。当他们发生时,您很可能会失去客户,除非您的应用程序已经需要连接到您的服务器才能运行(例如Twitter或Facebook)。
3)成为“坏公民”,胡乱操作应用程序包或留下孤立的文件。如果您这样做,至少要确保它们的名称清晰,以便明显与您的应用程序相关。
最重要的是要记住的是,您在用户的机器上没有安全性。那是他们的。这意味着他们拥有物理访问权限,这几乎使任何防止他们挖掘的尝试无效。您还可以这样看待:您的市场越技术化,您就越不可能比我们所有人都聪明,您的“安全性”将被破解。如果您为非技术受众设计,则通常可以认为他们不会费心去破解它或寻找一个破解方法。
您可以把资源花在让应用程序变得更好上,或者让自己对人们在试用期过后不使用它感到更好。其中一个可以增加销售额,而另一个则不会。
[编辑] 此外,我应该指出,破解这些东西最常见(如果不是最常见)的方法之一是修改二进制文件。因此,通过包混淆来破坏代码签名,实际上会让您暴露于该方法,因为您已经破坏了您拥有的较好的保护措施之一。大多数破解都涉及修改二进制文件,使得执行检查的例程总是返回成功的身份验证。

3
如果必须这样做,一种简单而常见的方法是使用嵌入在应用程序中的密钥来加密磁盘上包含敏感数据的文件。挑战在于如何使密钥安全。
查看Common Crypto摘要库。
这将保护免受几乎所有普通用户的攻击。尽管黑客可以通过足够的动机找到规避方法。

3
Allan Odgaard有一篇相当不错的文章,介绍如何使用OpenSSL为Cocoa软件生成/存储许可证密钥。可能值得一读。请参考此处

2
尝试将以句点开头的文件存储在某个文件夹中,然后设置文件的隐藏标志。一个好的隐藏文件位置是用户文件夹(〜/)基础下一个名字不太常见的文件夹中,因为那里有许多隐蔽的文件,所以很难知道哪些文件可以和不能删除。示例路径:〜/.xdarwinprofile或类似官方名称的东西。
以下是应该可行的隐藏文件代码:
#include <assert.h>
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <sys/attr.h>
#include <sys/errno.h>
#include <unistd.h>
#include <sys/vnode.h>

typedef struct attrlist attrlist_t;

struct FInfoAttrBuf {
    u_int32_t length;
    fsobj_type_t objType;

    union {
        char rawBytes[32];

        struct {
            FileInfo info;
            ExtendedFileInfo extInfo;
        } file;

        struct {
            FolderInfo info;
            ExtendedFolderInfo extInfo;
        } folder;
    } finderInfo;
};
typedef struct FInfoAttrBuf FInfoAttrBuf;


- (int)SetFileInvisibility:(NSString *)filePath state:(BOOL)isInvisible) {
    attrlist_t attrList;
    FInfoAttrBuf attrBuf;

    char *path = [filePath cStringUsingEncoding: NSUTF8StringEncoding];

    memset(&attrList, 0, sizeof(attrList));
    attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
    attrList.commonattr  = ATTR_CMN_OBJTYPE | ATTR_CMN_FNDRINFO;

    int err = getattrlist(path, &attrList, &attrBuf, sizeof(attrBuf), 0);
    if (err != 0)
        return errno;

    // attrBuf.objType = (VREG | VDIR), inconsequential for invisibility

    UInt16 flags = CFSwapInt16BigToHost(attrBuf.finderInfo.file.info.finderFlags);

    if (isInvisible)
        flags |= kIsInvisible;
    else
        flags &= (~kIsInvisible);

    attrBuf.finderInfo.file.info.finderFlags = CFSwapInt16HostToBig(flags);

    attrList.commonattr = ATTR_CMN_FNDRINFO;
    err = setattrlist(path, &attrList, attrBuf.finderInfo.rawBytes, sizeof(attrBuf.finderInfo.rawBytes), 0);

    return err;
}

我修改了这段代码,是根据这个问题的答案进行的修改。你可以在此处找到更多有用的信息: 如何使用objective-c使一个文件在Finder中不可见

我尚未测试过这段代码,但它应该能够正常工作。实际上,这段代码可能是不必要的,只需在文件名前面加一个点来保存文件即可。

如果您具有管理员权限,可以对该文件执行sudo chmod,并将其设置为只读,但您不应该让您的应用程序询问用户密码。


0

这个解决方案对我非常有效。试试这个:https://github.com/nielsmouthaan/SecureNSUserDefaults。它将在您的UserDefaults文件中存储加密的布尔值/字符串/浮点数/整数。希望这正是你想要的。确保你下载并添加CocoaSecurity(请参阅SecureNSUserDefaults GitHub页面以获取下载链接)到你的项目中。CocoaSecurity是SecureNSUSerDefaults所必需的元素,因此您不需要将其导入任何文件中。您还需要下载Base64,它是CocoaSecurity所必需的元素。您还需要将Base64添加到您的项目中,但不需要将其导入任何文件中。

使用方法

在任何您想使用加密方法的地方导入头文件即可。

#import <SecureNSUserDefaults/NSUserDefaults+SecureAdditions.h>

然后,设置一个加密密钥,可能在您的awakeFromNib方法中:

[[NSUserDefaults standardUserDefaults] setSecret:@"your_secret_goes_here"];

我建议生成一个随机的数字和字母字符串。然后,您必须将信息存储在您的UserDefaults文件中。
[[NSUserDefaults standardUserDefaults]
    setSecretObject:@"your_secret_object"
    forKey:@"the_key_your_object_will be_stored_under"];

使用以下方法检索字符串:

NSString *retrievedData = [[NSUserDefaults standardUserDefaults]     
    secretStringForKey:@"the_key_your_object_will be_stored_under"];

希望这能帮到你!


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