I need to set up user proof time keeping in my current project. I have found a lot of different question around this, but none that seem to have the answer I am looking for. These are the questions i have looked at so far:
XCODE: How to get/verify ACCURATE timestamp from device
Is it possible to get the atomic clock timestamp from the iphone GPS?
How can I get the real time in iPhone, not the time set by user in Settings?
I have several options for getting a time from a server connection but I need to have an offline solution too.
1.
It seems that using CLLocation gets the same time as as the device clock. Is there away to get the actual GPS time?
2.
I know the system time settings are not a public API thus can't be changed. Is it possible to find out if the device has the auto time setting turned on? If the auto time is on then I can rely on the system time for my purposes and if it's off then record that so I know that the time recorded is not to be trusted?
Just wanted to post my solution, incase some one else has the same issue.
After much research i found that getting GPS time of time setting info was not possible.
This solution isn't perfect nor real time but works for my purpose.
I have implemented a time check using cloud time each time the app comes on line. When the device re-establishes a server connection to sync events created off line i have put a verification that takes the last object device time and the new object device time and calculates the elapsed time between the two. (using NSdates so that daylight savings is covered) then do the same with the last available server time and the most recent server time. I then compare the results and if they are not within my margin of error the events are marked as invalid.
Hope that makes sense and is helpful for others.
Related
Currently I'm writing an app that will need every iOS devices to have some sort of synchronized time in order to function correctly. I know I can use NSDate to get current time, but I'm not sure if all iOS devices (no matter what location setting it has, or maybe user sets the time manually) will have same NSDate. The synced time has to be accurate enough (< 10ms difference maximum). Can I just use NSDate directly?
No, you cannot rely on NSDate to give you this information.
You can use a Real Time server to provide this information.
Check, it may help you.
Check also about NTP protocol, you can easily use this github project to get from a trusted time server, the current time, whiteout rely on the device.
but I'm not sure if all iOS devices (no matter what location setting it has, or maybe user sets the time manually) will have same NSDate.
Obviously they won't, because some people will set the time manually, so it could be quite far off.
Settings -> General -> Date & Time -> Switch off "Automatically" -> set the time to whatever you wish. So clearly what you ask for cannot be possible.
If you want synchronisation, then the only way you can do this between multiple device is with a central server that keeps the time, and everyone uses the time reported by that server, in your code.
I have an application that works with timeout (let's say -> ring in 3 days). My problem occurs if a user change the device local time while being offline because I am comparing two NSDate (the final date and today) to check that timeout.
So I am trying to get notified when a user made a significant time change (several hours or days) in order to update my timers depending on the difference between before and after the update.
I found the UIApplicationSignificantTimeChangeNotification, which does :
Posted when there is a significant change in time, for example, change to a new day (midnight), carrier time update, and change to or from daylight savings time.
That nearly fits but I can't figure out how to get the "old" time in order to get the difference. I can't rely on a webserver neither because the app should be running in offline mode.
Any idea or suggest is welcome ;)
I finally find a way to solve my problem by using the CPU time (which is always constantly increasing except on reboot).
First time the app is launched, I get the Real time and the CPU time.
Then, when I need to check if time has been changed, I just take
the Real time at first, I add to it ( the current CPU time - the CPU time at first).
This give me the correct time.
Note: take care to use the real CPU time, not the one used by timer because it's stop when device go to sleep.
You should store the current time of your device, when your application goes into background. When the application comes into foreground, you should take the current time of your device. Now measure the difference between these 2 dates. If it is less than zero, it means, the user has set the device with previous date and you should throw the error of time out. If the difference is greater than 0, then you should compare current time with actual finish date.
One more indirect way is to start the location tracking of your device. Keep it on even when the app goes into background. When your didUpdateLocation delegate will hit by system, you will receive CLLocation object in argument. This location object is having currentTime details. Compare the time of last location and current location. If it is negative, user has bluffed with time. Its time to take the action.
The scenario is a iPhone user who doesn't want the time to automatically update when he travels abroad and thus has disabled the system setting "Set Automatically" for time zones, leading to [NSTimeZone systemTimeZone] not updating for his new location.
As a developer, can I still find out the current local time and time zone for the (possibly new) country the device is in?
No. Not without some work anyway, and maybe not with some work.
If the user has disabled auto time zone setting, the only time zone you get to know about is the one that they've told their phone to use. You don't get to bypass their preferences on that. Unfortunately you also don't get to find out if they've done that. All you get is a time zone, but why that's current is not something you can answer.
If you're determined, you might try using Core Location to get their latitude and longitude, and work out a time zone from that. Doing that reliably may be a challenge-- the official IANA time zone database includes lat/long, but only at one location within each time zone. There are services like AskGeo that claim to solve this problem (they might be fantastic, I haven't tried them). But that obviously requires a network connection, and people traveling to other countries are probably less likely than average to have mobile data access.
I want to deploy managed iOS devices to employees of the company, and the app they will use will timestamp data that will be recorded locally, then forwarded. I need those timestamps to be correct, so I must prevent the user from adjusting the time on the device, recording a value, then resetting the date and time. Date and time will be configured to come from the network automatically, but the device may not have network connectivity at all times (otherwise I would just read network time every time a data value is recorded). I haven't seen an option in Apple Configurator to prevent changing the date and time, so is there some other way to do this?
You won't be able to prevent a user either changing their clock or just hitting your API directly as other commentators have posted. These are two separate issues and can be solved by having a local time that you control on the device and by generating a hashed key of what you send to the server.
Local Time on Device:
To start, make an API call when you start the app which sends back a timestamp from the server; this is your 'actual time'. Now store this on the device and run a timer which uses a phone uptime function (not mach_absolute_time() or CACurrentMediaTime() - these get weird when your phone is in standby mode) and a bit of math to increase that actual time every second. I've written an article on how I did this for one of my apps at (be sure to read the follow up as the original article used CACurrentMediaTime() but that has some bugs). You can periodically make that initial API call (i.e. if the phone goes into the background and comes back again) to make sure that everything is staying accurate but the time should always be correct so long as you don't restart the phone (which should prompt an API call when you next open the app to update the time).
Securing the API:
You now have a guaranteed* accurate time on your device but you still have an issue in that somebody could send the wrong time to your API directly (i.e. not from your device). To counteract this, I would use some form of salt/hash with the data you are sending similar to OAuth. For example, take all of the parameters you are sending, join them together and hash them with a salt only you know and send that generated key as an extra parameter. On your server, you know the hash you are using and the salt so you can rebuild that key and check it with the one that was sent; if they don't match, somebody is trying to play with your timestamp.
*Caveat: A skilled attacked could hi-jack the connection so that any calls to example.com/api/timestamp come from a different machine they have set up which returns the time they want so that the phone is given the wrong time as the starting base. There are ways to prevent this (obfuscation, pairing it with other data, encryption) but that becomes a very open-ended question very quickly so best asked elsewhere. A combination of the above plus a monitor to notice weird times might be the best thing.
There doesn't appear to be any way to accomplish what you're asking for. There doesn't seem to be a way to stop the user from being able to change the time. But beyond that, even if you could prevent them from changing the time, they could let their device battery die, then plug it in and turn it on where they don't have a net connection, and their clock will be wrong until it has a chance to set itself over a network. So even preventing them from changing the time won't guarantee accuracy.
What you could do is require a network connection to record values, so that you can verify the time on a server. If you must allow it to work without a net connection, you could at least always log the current time when the app is brought up and note if the time ever seems to go backwards. You'll know something is up if the timestamp suddenly is earlier than the previous timestamp. You could also do this check perhaps only when they try to record a value. If they record a value that has a timestamp earlier than any previous recorded value, you could reject it, or log the event so that the person can be questioned about it at a later time.
This is also one of those cases where maybe you just have to trust the user not to do this, because there doesn't seem to be a perfect solution to this.
The first thing to note is that the user will always be able to forge messages to your server in order to create incorrect records.
But there are some useful things you can use to at least notice problems. Most of the time the best way to secure this kind of system is to focus on detection, and then publicly discipline anyone who has gone out of their way to circumvent policy. Strong locks are meaningless unless there's a cop who's eventually going to show up and stop you.
Of course you should first assume that any time mistakes are accidental. But just publicly "noticing" that someone's device seems to be "misbehaving" is often enough to make bad behaviors go away.
So what can you do? The first thing is to note the timestamps of things when they show up at the server. Timestamps should always move forward in time. So if you've already seen records from a device for Monday, you should not later receive records for the previous Sunday. The same should be true for your app. You can keep track of when you are terminated in NSUserDefaults (as well as posting this information to the server). You should not generally wake up in the past. If you do, complain to your server.
Watch for UIApplicationSignificantTimeChangeNotification. I believe you'll receive it if the time is manually changed (you'll receive it in several other cases as well, most of them benign). Watch for time moving significantly backwards. Complain to your server.
Pay attention to mach_absolute_time(). This is the time since the device was booted and is not otherwise modifiable by the user without jailbreaking. It's useful for distinguishing between reboots and other events. It's in a weird time unit, but it can be converted to human time as described in QA1398. If the mach time difference is more than an hour greater than the wall clock time, something is weird (DST changes can cause 1 hour). Complain to your sever.
All of these things could be benign. A human will need to investigate and make a decision.
None of these things will ensure that your records are correct if there is a dedicated and skilled attacker involved. As I said, a dedicated and skilled attacker could just send you fake messages. But these things, coupled with monitoring and disciplinary action, make it dangerous for insiders to even experiment with how to beat the system.
You cannot prevent the user from changing time.
Even the time of an Location is adjusted by Apple, and not a real GPS time.
You could look at mach kernel time, which is a relative time.
Compare that to the time when having last network connection.
But this all sounds not reliable.
In iOS, I need to know the actual time (UTC), not the time of the device. In other words, it should not be possible for the user to tamper with the time or date.
Anything that requires a network connection is not good (so accessing a time server is not an option).
AFAIK, there are 2 theoretical ways of achieving this:
Use the timestamp from the GPS satellite signal
Get the current time from the carrier
Problem is that this information is not exposed by any API in iOS.
Is there another way?
Most solutions you could possibly find (including getting GPS data from CoreLocation to access the time information) are flawed because they are depending on the actual device to access time time. You will need to connect to a time server (i would suggest to check for NTP server). I was looking at the core telephony framework and couldn't find anything that would provide the network time. You might want to fill a bug report and request apple to expand one of the classes to include the time.
You could have a look at secondsFromGMTForDate: and secondsFromGMT in NSTimeZone. If the GMT offset increases/decreases when the time of the device is changed, these provide a way to correct your timestamps to GMT (and probably convert to UTC).
You can't get to the raw GPS data and the timestamp property of the CLLocation in locationManager:didUpdateLocations: is set with the system clock