加密NSURLCache的更好方法是什么?

eme*_*gro 5 nsurlcache nsurlprotocol ios nsurlsession alamofire

我想加密/解密NSURLSession使用AES256的所有缓存数据.我是使用Alamofire的新手,但我认为可以在不涉及图书馆本身的情况下进行.

我不确切知道在缓存之前加密数据的最无缝方式是什么,并在从缓存中检索后对其进行解密.

我看我可以使用Alamofire的SessionDelegate和方法dataTaskWillCacheResponse,并dataTaskWillCacheResponseWithCompletion进行加密,但我没有看到从缓存中做解密所提取的数据有关的任何东西.

另一方面,我正在考虑NSURLProtocol重写的自定义,cachedResponse但我没有看到与该响应的缓存有关的任何内容,只有提取的数据.

总而言之,我不知道是否有可能实现这一点,或者我必须在NSURLSessionDelegate/SessionDelegate和之间使用混合NSURLProtocol,或者可能使用子类NSURLCache来完成工作并将其传递给Alamofire会话,或者有更简单的东西,或者我非常错误:P

任何帮助将非常感激.


编辑

我正试图通过下一个实现来实现它.首先是缓存的一个非常简单的子类:

class EncryptedURLCache: URLCache {

    let encryptionKey: String

    init(memoryCapacity: Int, diskCapacity: Int, diskPath path: String? = nil, encryptionKey: String) {

        guard !encryptionKey.isEmpty else {
            fatalError("No encryption key provided")
        }

        self.encryptionKey = encryptionKey
        super.init(memoryCapacity: memoryCapacity, diskCapacity: diskCapacity, diskPath: path)
    }

    override func cachedResponse(for request: URLRequest) -> CachedURLResponse? {
        objc_sync_enter(self)
        defer { objc_sync_exit(self) }
        return super.cachedResponse(for: request)?.cloneDecryptingData(withKey: encryptionKey)
    }

    override func storeCachedResponse(_ cachedResponse: CachedURLResponse, for request: URLRequest) {
        objc_sync_enter(self)
        defer { objc_sync_exit(self) }
        super.storeCachedResponse(cachedResponse.cloneEncryptingData(withKey: encryptionKey), for: request)
    }
}
Run Code Online (Sandbox Code Playgroud)

并且缓存响应的扩展以返回加密/解密数据

extension CachedURLResponse {

    func cloneEncryptingData(withKey key: String) -> CachedURLResponse {
        return clone(withData: data.aes256Encrypted(withKey: key))
    }

    func cloneDecryptingData(withKey key: String) -> CachedURLResponse {
        return clone(withData: data.aes256Decrypted(withKey: key) ?? data)
    }

    private func clone(withData data: Data) -> CachedURLResponse {
        return CachedURLResponse(
            response: response,
            data: data,
            userInfo: userInfo,
            storagePolicy: storagePolicy
        )
    }
}
Run Code Online (Sandbox Code Playgroud)

这是有效的,但仅适用于我使用标头安装的mockable.io Cache-Control: max-age=60.我也在测试SWAPI http://swapi.co/api/people/1/和Google Books https://www.googleapis.com/books/v1/volumes?q=swift+programming.

在所有三种情况下,响应都已正确加密和缓存.我正在进行测试,切断Internet连接并设置会话配置requestCachePolicy = .returnCacheDataDontLoad.

在这种情况下,对mockable.io的请求被正确解密并从缓存中返回,但其他人说NSURLErrorDomain Code=-1009 "The Internet connection appears to be offline.".这非常奇怪,因为根据该策略,它必须说NSURLErrorDomain Code=-1008 "resource unavailable"是否有可能返回缓存的数据.如果解密时出现错误,则表示序列化为JSON对象时出错.

我还使用公共共享缓存进行了测试,它按预期工作,使用该策略返回数据.我认为这可能与SWAPI和GBooks响应中缺少缓存头有关,但是这个测试有效,它返回缓存的数据.

然后我做了另一个测试:使用我的缓存但没有加密/解密数据,只需按原样克隆返回的缓存响应,没有结果.然后我尝试了最后一个非常愚蠢的测试:为了避免克隆响应,只需返回cachedResponse然后IT工作.h***是如何可能的?如果我克隆cachedResponse以注入我的加密/解密数据,它就不起作用了!即使在Apple的例子中,他们也在不遗余力地创建新的缓存响应.

我不知道错误在哪里,但我会在一两分钟内跳过窗户.

请帮忙吗?非常感谢.


编辑2

我正在使用Apple的DTS工程师更改电子邮件,结论是这不可能实现这一点,因为支持CF类型比基础对象做更多的逻辑,在这种情况下,它正在对传递的URLRequest进行验证当系统缓存响应时,它,当我使用常规NSCachedURLResponse进行克隆时,我无法传递它.

当系统根据请求进行验证时,没有一个可以匹配.

dga*_*ood 4

据我所知,没有办法拦截来自委托端的缓存检索调用,并且我不认为自定义协议甚至会被要求处理来自缓存的请求,但我可以错误的。所以你的选择可能是:

  • 在发出 URL 请求之前,明确向缓存请求数据。
  • 在实际处理响应的代码中添加代码,以便它识别数据已加密并解密。

    例如,当您将其存储到缓存中时,您可以在标头中插入一个附加标头,以指示缓存的数据已加密。然后,当您在返回时看到该神奇标头值时,将其解密。

  • 编写 NSURLCache 的子类并在那里处理解密(理想情况下,将磁盘上的数据存储在不同的文件中,以避免破坏应用程序中使用普通缓存的任何请求)。