skip to Main Content

I recently discovered that HTTPCookieStorage stores my application’s secure JWT tokens as searchable text in a file located at <App Bundle Path>/Library/Cookies/<bundle id>.binarycookies.
I had previously presumed that Apple would encrypt the tokens before storing them to disc, especially given that they are marked as secure tokens.
I’ve searched the Internet, and most responses admit that this is true, but suggest that this is not an issue because of Apple’s Data Protection technology (which uses 256-bit encryption when the device is locked). However, when the device is unlocked or jailbroken, these cookies would be readily accessible. I want to ensure that my application’s JWT tokens are encrypted even when the device is unlocked or jailbroken.

I’ve searched the documentation for HTTPCookieStorage for any settings to encrypt secure cookies before saving them to disc and found no built-in option.

2

Answers


  1. Chosen as BEST ANSWER

    Turns out that HTTPCookieStorage can be subclassed. I ended up implementing an in-memory solution. This could easily be modified to use Keychain. In-memory is good enough for my current solution.

    class SecureCookieStorage : HTTPCookieStorage {
        private var inMemoryCookieStorage : [String: [HTTPCookie]] = [:]
        private let cookieQueue = DispatchQueue(label: "secure.cookie.storage", attributes: .concurrent)
    
        override func getCookiesFor(_ task: URLSessionTask, completionHandler: @escaping ([HTTPCookie]?) -> Void) {
            guard let host = task.currentRequest?.url?.host else {
                completionHandler(nil)
                return
            }
            
            cookieQueue.sync { [weak self] in
                guard let self = self else { return }
                let cookies = self.inMemoryCookieStorage[host]
                completionHandler(cookies)
            }
        }
        
        override func storeCookies(_ cookies: [HTTPCookie], for task: URLSessionTask) {
            guard let host = task.currentRequest?.url?.host else {
                return
            }
            
            cookieQueue.async(flags: .barrier) { [weak self] in
                guard let self = self else { return }
                self.inMemoryCookieStorage[host] = cookies
            }
        }
    }
    

    Then, set up URLSessionConfiguration to use SecureCookieStorage

    let configuration = URLSessionConfiguration.default
    configuration.httpCookieStorage = SecureCookieStorage()
    let urlSession = URLSession(configuration:configuration)
    

  2. If you really need it to be "secure" you shouldn’t store it into the HTTPCookieStorage. Rather use the Keychain and then add the cookie whenever needed to your request. But I don’t get why it needs to be so private, that the user can’t read it. If they want they could also intercept the cookie when sent with a request.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search