Does NSURLCache remove expired cached responses? - ios

Apple has supported disk caching as of iOS 5.0. I was using a home-rolled solution before, but I'm testing NSURLCache in hopes of finally using it since I've seen strange behavior in the past.
One of the more perplexing issues I'm having is that cachedResponseForRequest: returns expired requests. I've been testing by setting forward the clock on the iPhone I'm using. Parsing the headers clearly shows that the device time is ahead of the expiration date.
I'm willing to accept that there may be a background task that prunes expired requests on a regular interval. I have done tests where I actually wait to see if the request expires "naturally", and it doesn't.
Did Apple just fail to implement cache invalidation correctly?
I'm testing using a Charles proxy. It's a tough problem and I don't envy anyone who has to implement cache invalidation, but iOS is supposed to be a mature SDK by now.

There are two http caching mechanisms: expiration and validation.
If a response has not expired, the client can serve it from the cache without making a request to the server.
If it has expired the client can make conditional requests using the If-Match or If-Modified-Since header entries.
If the server responds with 304 Not Modified, the client can use the data from the cache even if it has expired.
For more details have a look at http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html.

Related

Ionic 6 angular capacitor set cookies on ios

i have a ionic 6 app with angular and i'm using external APIs to login user and retrieve some data.
When the user authenticates, the server responds with a Set-cookie header; everything works fine both on browser and android application.
On iOS looks like the set-cookie header received in the response is doing nothing.
I'm trying also to use cordova-plugin-wkwebview-inject-cookie on my app.component.ts:
this.platform.ready().then(() => {
if (this.platform.is('ios')) {
wkWebView.injectCookie(environment.config.baseUrl, '/');
}
});
but the cookie is not stored, so every next request get 401 response:
After a lot searching about this problem, I found this thread in capacitor github issues;
Long story short: It's not an problem or issue, actually it's a security decision take by Apple, like Thomas Vidas said in the same thread here:
It's several things, the main one being it was a deliberate change from Apple on iOS 14 and up called "Intelligent Tracking Prevention" (ITP) which disables all cookies on domains not listed as an App Bound Domain. It's not due to the capacitor:// protocol. ITP made it so document.cookie calls were intended to silently fail to prevent user tracking. If your server.hostname and App Bound domains are set up properly, it may work but could have other unintended consequences (such as Apple potentially rejecting your app) so we don't recommend it.
So, I recommend you to read the entire thread to get some insights, because it's a think that capacitor team doesn't have a solution.
I hope it will help you!

Images in emails are inconsistently being cached in iOS Outlook App

While testing images being loaded from an email in my iOS Outlook app, I see inconsistencies with how the app caches them. These images are loading from external sources (i.e. HTML img tag with src pointing to a server, not images that are embedded/attached). The app makes several requests to the same image source as you navigate around. Some of these requests contain the HTTP_IF_NONE_MATCH header but there is a lot of inconsistency. I don't think it's caching them correctly. I've included more details below. it looks like it's causing my image to be loaded several times when the person is browsing the email/their inbox.
The reason this is a problem for me is that I'm building an email tracking tool that relies on a pixel tracker inside the email. I'm trying to determine how many times my email is opened by its various recipients. So this inconsistency is causing misfires for the tool unfortunately. While I realize that could be considered consequential limitation of relying on the app, I'm wondering if the lack of image caching is a larger issue that could be addressed. It is effectively firing requests to load the image repeatedly so that is eating up mobile data unnecessarily.
Is there a way to improve its caching somehow? I'm also looking for any other ways to determine requests coming from the same phone. Here's what I see in my server log when dealing with an email that contains my pixel tracker.
Push notification for email received on iPhone
Click the app to load the inbox -> Tracker request fired for 1st time (i.e. image loaded for first time)
Open email -> Tracker request fired for 2nd time (without any HTTP_IF_NONE_MATCH header)
Go back to inbox -> Tracker request fired for 3rd time but this time it includes HTTP_IF_NONE_MATCH header. Note previous requests did not include this header even though it's the same URL so some inconsistency indicating it did not cache it
Open email for the second time -> Tracker request fired for 4th time but it did not include the HTTP_IF_NONE_MATCH header (inconsistency with 3rd time, which had header)
Go back to inbox -> No request fired
Open email for third time -> Tracker request fired for 5th time and it included HTTP_IF_NONE_MATCH header (so inconsistency between this and 4th request, which did not include it)
From here on, repeating any of the above steps would trigger requests but would always include the HTTP_IF_NONE_MATCH header successfully. I also tested changing folders, refreshing the inbox, replying to emails etc. While this triggered tracker requests as well, they also included the appropriate header.
However, I noticed that closing the app (by swiping it off) and then opening it again effectively caused the behaviour to reset. The 1st, 2nd and 4th requests would still not include the header while the others would. Note the same happens on data vs wifi.
Generally speaking, it looks like the iOS app is repeatedly loading the images that it should have already cached. Outlook desktop clients work great because it only fires 1 request to load the pixel. For the Outlook Android app, it seems to do a better job caching the image. It makes 2 or 3 requests the first couple of times you open the email but the 2nd/3rd requests always include the header. After that, it stops loading the image altogether so it must be caching it on the phone somehow. Since the Android app functions fairly differently, this is what lead me to believe it may be an issue that could be resolved in the app itself. However, as I said above, I'm looking for alternative ways to determine how to track the user.
Another way I normally rely on is to set a cookie to indicate an open just happened by that device. I then simply skip these false positives to avoid the repeated requests. However, because of the nature of iOS apps needing to whitelist third-party cookies of web requests within the code, each subsequent request is not sending my cookie along either. Here's a related question as well. I confirmed the Safari settings do not block 3rd party cookies in case it conflicts.
Alternatively, if there's another way to tell a unique device, I could figure out how to skip repeated opens for that phone on the server. I checked the rest of the request headers. The only thing that's somewhat identifiable is a combination of user-agent and IP address but that seems very unreliable to me. Two people in the same office with the same corporate phone could be on the same wifi so I think that would fire false negatives instead.
Is there another way to determine the device is opening it multiple times? Ideally if it sent a unique identifier or something, that would be very useful.
Is there a way to force the app to cache the image (this would heavily reduce the misfires) via say some response header?

Are Universal Links cached in iOS? Do they work offline?

I tested Universal Links in iOS by turning on Airplane mode and saw that the correct application was opened (instead of a website)
This indicates some level of "caching" the apple-app-site-association.
I want to determine the extent to which this is cached, so I can determine
What UX edge cases are there (e.g. Offline for x days)
What security considerations are there (e.g. MITM / SSLStrip + .well-known/URL)
etc.
Ideally I would like to have details if additional logic is employed (conditional caching if HTTPS employed, DNSSec, etc)
The exact behavior here is (intentionally?) unclear from Apple. Here is my personal experience, gleaned partly from official documentation and partly from helping thousands of apps implement Universal Links at Branch.io.
The apple-app-site-association file is cached once when the app is first installed.
If this initial scrape fails, in almost all situations it will not be reattempted. The only exception to this is if the initial return is a 5xx error, in which case a limited number of retries may occur. This is not well-documented, and is not covered in Universal Links documentation at all. You can find a mention in the Shared Web Credentials docs.
The file is not checked at all when a Universal Link is opened. This is why you are able to get Universal Links behavior in airplane mode.
The file does not expire. Once it is cached, it sticks permanently for as long as the app is installed.
The file will be re-checked when installing an app update.
The file must be accessible via a valid SSL connection at either https://example.com/apple-app-site-association or https://example.com/.well-known/apple-app-site-association. If there are redirects of any kind, this will fail.
It is theoretically possible to MITM the request if you are able to install a new SSL certificate directly on the device in question. Charles Proxy for example uses this approach for debugging. I have never seen or heard of this being exploited, and the damage would be quite limited because the domain still has to be specified inside the app itself.
I found a way to get around the caching issue. The cache is bound to the domain name, so for every time you want iOS to request apple-app-site-association you can create a new subdomain, and configure iOS to use that subdomain as the universal link for your app.
Extremely hacky, but it is the only workaround that worked for me.

iOS Networking data cache issue

I am developing app. It includes login page. After login I receive the response json. I tried the login multiple times with two different accounts.
Lets say account A & B. If I build and run fresh build on device and login with account A. I get the correct response. If I logout and re-login with the account B. In this case, I get the old response of the account A.
The problem remains if I do vice-versa. There is no issue with the web services.
I need to know whether there is issue with response caching in ios. I tried to implement this with the NSURLConnection, NSURLSession, and AFNetworking. The problem stays.
I have implemented the same for the android device. no response issue on android.
Can anybody suggest anything on this situation. Any suggestions are highly appreciated.
NSURLCache has no notion of accounts. You'll have to either tell it to remove all cached items or disable caching. Realistically, caching JSON responses is almost never the right thing to do, so you should probably disable caching for those requests.

Send post data securely from iPhone

I have the following issue:
I've understood how to create a secure login between an iPhone app and a WebServer (SSL,Https).
My question is after creating the session token, how do I make sure that if a hacker intercepts it, in the subsequent POST requests I receive data from the same user?
I ask this because I would have to send the session token each time a request is made right? (to be able to identify the user).
I want to prevent multiple things:
Session hijacking where someone would sniff the users token and send data instead of him (like a highscore or something)
Data injection using data that would not be normally sent from my app like a 1.000.000.000 highscore (possible score but not easily attainable).
I have been looking at:
UDID
User Agent (if it's not from the app name of my app it's not good, the hacker would actually have to guess I do this check or download my php files somehow right?)
The app is from the AppStore. If the request comes from an app that hasn't been approved by Apple it's not ok. I'm not actually sure if you can test this or not. If this works a hacker would have to actually submit an AppStore and download it to insert faulty data into my database which I hope nobody has time for.
The MAC address. Not sure if allowed by Apple. The IP doesn't work because a valid user might change IP's.
Cookies from what I've seen can be easily traced and see what data is inside them.
Maybe I'm not asking the right question here so it could actually be how can I make sure the data I receive is from the correct user and the correct application?
The purpose of SSL around your POST requests is to prevent interception by a third-party in transit. If a hacker can get to it, it means the token was either leaked on the client (rooted device), server (insecure application logging/debugging) or they broke SSL. (unlikely)
You could perform some advanced checking by capturing device UDID (apple doesn't like this) or comparing to source IP, but it is going to be a lot of effort for questionable security improvement.
Just ensure everything sensitive is in SSL and you should be ok.

Resources