We have an android(or iphone) client we are developing. The client allows the android user to send entries to a server which we also develop. If the client does not have data services (GPRS) at the moment the user sends the entry to the server, the client also supports saving the entry to an offline database and sending it later to the server.
One important aspect of the whole process is accuracy of the timestamps on which the user sent the entry to the server (whether the entry is made in real time or sent by the client from the offline database)
When available on the client, we get a GPS location and are able to use the GPS timestamp to send that to the server (or save the GPS timestamp on the offline DB and send it later to the server). However if the user has turned off the GPS (and all other location services), the device will not have a GPS fix and therefore the server can not determine accurately when an entry was made.
We can not use the local device clock as the user may change the clock to make entries on different times than they actually occurred (these entries are part of the users salary so he might have an interest to "fix" them).
So basically I am searching for a way to determine as best I can the time some entry was made when I can not trust the internal clock of the mobile. The algorithm should support both entries sent in real time or entries sent from an offline DB. the algorithm should also support cases where the user changes the time of the mobile, turns the mobile on/off, turns the GPS on/off while the application is running on the mobile etc...
Few ideas that I thought of:
Although I can not trust the mobile's time, it can still perform as a stop watch:
Have a class that will loop until the application exists, the loop will sleep 1 second and increase an internal clock variable by 1 second. On every GPS location my code gets we update the internal clock variable. This way I have an absolute clock that came from outside the device (from the GPS) and when the client sends an entry to the server, we can use the internal clock as an absolute time.
PROS: the user can not modify this clock as it is only updated when we get a location from the GPS
CONS: the application needs at least one GPS fix before the user can make any reliable entries
I can take advantage of the fact that the server has an accurate clock which is correct. If the client would send to the server info that the age of the entry is 10 minutes, the server could use its internal time and know the exact time the entry was made on.
The biggest problem is how to know the entry age? I thought about saving the entries to the offline DB with an age of 0, then every 1 second increase the age of the entry in the DB. The problem is that if the app is closed and/or the device is off this will now happen
This is where I am currently stuck. Any ideas on how to solve this are more than welcome
Thanks
Here's how I handle this issue for iPhone. When the app starts, I call my server and ask for the current GMT time (you could also call a public NTP server if you preferred). I then compare it to the system time. If it is different by more than X then I popup a message saying, sorry your system time is wrong so you can't use the app until you fix this. I then monitor for the user changing the system time while the app is running and if they do that, then I do the compare again (and popup the error message if the time is off by more than X). This ensures that their system time is always correct (within some reasonable allowance) and you can trust [NSDate date]. However, this solution does require a valid network connection. If this solution works for you, I can post the sample code.
i think i am going to combine Jules and Joel's answers into one solution which will provide for my needs the best solution:
since the user might change the clock when the mobile doed not have GPRS, just detecting the time change event will not help us as we can not validate at that moment the new time is correct.
As Joel recommended i will pull the time from my server when my application is started (at that point i still must have communications with the server or else my application will not start). The time pulled from the server along with the current device upTime will be saved.
when the user wants to make an entry i will calculate the current time using (Server Base Time + Current UpTime - Base UpTime). this way i will have an independent source of time regardless of the current clock of the device
this will defenitly work on android
on iPhone we will try to use something out of http://www.cocoadev.com/index.pl?FindingUptime to get the upTime
Jules & Joel, thanks for your answers!
Look into android.os.SystemClock. Specifically, elapsedRealtime() returns a time since the phone was switched on, which is not affected if the clock is changed by the user.
You can correlate times in event the phone is switched off by having code that runs when it is switched on and checks the realtime clock. As the clock can't be changed when the phone is off, I suspect you could use this to put together a system that will catch any simple attempts at cheating. (If the user roots the phone all bets are off -- they could modify the behaviour of the APIs from under you).
Running code every second will kill the phone's battery life. Most phones would be unlikely to last a day if you did this.
Related
Background
The company I work for is creating an app that collects information from various device events and sensor data.
One of the things we would like to be able to do is use time to process the data when it gets to the server.
We would also like there to be an acceptable amount of "offline time" allowed, i.e., the app could be used for its purpose even while offline until the next server data update is required etc.
Problem
One issue is that the user can just change the device time.
We overlooked this, and have been able to successfully generate events for the previous day, which would mean that our app could be fooled in situations where device time is a factor, which is very uncomfortable.
Imagined solutions
Obviously I can ensure that the app is always sync'd to the server before it starts collecting important data, and then use server time and make all further time relative to that.
Another way might be to keep a reference to something like the last update time or even the app install time and work out time relative to that.
Questions
How do people get around this typically?
Are there any libraries out there that can be used to enforce real device time?
Thanks guys
I have an application that relies heavily on current timestamps. Currently, when user submits a request, I get the current timestamp in UTC using System.currentTimeMillis(). While this works fine, it becomes a problem when the user starts manipulating their Date/Time on their device and would result as inaccurate timestamps.
Why do it on the client then? Why not just handle it on the server? Well, my application needs to work offline. All my requests get pushed into a jobQueue when connectivity to the internet is unavailable. In these cases, I must have the original time wherein the user did the action so if I submit a request at 4:02pm, but due to network problems, server will only receive it around 7:30pm, server MUST know that I sent the request at 4:02pm.
Now what options have I considered?
Upon user login, I sync the device time with the server time and store that time locally. If any user manipulation occurs while the user is logged in, I'll have a BroadcastReceiver listening in onto any intents of Date/Time manipulation, then store the offset so that whenever a user submits a request, I will calculate the synced time with the offset to ensure the timestamp is accurate.
Have a server sync api done in the backend and set up a service within my application to continuously sync up with the server time and look for any drift while also listening in onto any user manipulation.
Use push notifications and listen downstream for time synchronization adjustments while also listening onto any user manipulation.
I could also make use of the NTP servers to synchronize time with my device.
I'm not entirely sure which would be the most optimal (assuming I have listed down all the possible solutions). If there are other solutions I haven't thought of, please let me know.
P.S. If I happen to use the BroadcastReceiver to listen onto any datetime manipulation on the device, how would I even calculate the offset in that?
It has been some time since I asked this question and there hasn't been any elegant answers to the problem so after some research and some trial and error, I decided to take the NTP route and after some digging around, I found a nice library that does the entire thing for you.
It can be found here:
NTP TRUE TIME
Credits to these guys who had made life a lot easier.
You must sync with the ntp servers just once and from there on, they will calculate the Delta for us giving us accurate UTC regardless of SystemClock time.
For time synchronization you can implement like getting time zone from server. Once we have timzone we can get the current time of server.
My customer make a request for their commercial app is to automatically expire the content after downloading into the device in 7 days, even in the following cases:
+ without the internet connection to connect and check the expired time from the server
+ stop the customer try to maliciously modify the time in their device to expand the expired time
When the content expired, it will be removed from the device and unavailble to watch any more.
After a few days researching on Google, I still not find out the appropriate approaches.
Why can't you just add an expiration date at the content when you download it? And then check if is expired or not locally, without any control server-side.
There is a few suggestions but not of them is enough to cover all the cases maybe it will be useful if you combined them :
1- get the time based on the last know-location .
2- get the network time so the user
changing their device time wont matter (requires an internet
connection)
There isn't a great solution to this. You do have a couple of options, none of which are perfect.
Option 1 - use date / time from last known location
This will require you to request GPS access in your application, which may concern users, if the app doesn't have a valid need for tracking the users' locations. But basically get the last known position, and in the Location object returned would be the time as of that last location check. Two things could prevent this from working 100%. First, with newer version of Android, users can disable certain app permissions. This means they could disallow GPS access to your app. To combat this, you could check this on app startup and inform the users they cannot access any content unless GPS access is enabled. Second, if the user has no GPS signal, the last known location may have been from days ago, meaning the "current time" will be frozen as of the last GPS signal. Also, some devices don't have GPS chips, so this would not work for them.
Option 2 - Try to detect system date / time changes by keeping a log of the date / time in your app.
Basically, this will take some work to keep track of the system date / time on each launch, as well as the duration of each session in your app. With this log, you could compare to the current / date time and see if the user is rolling back the clock. This wouldn't be perfect, as a smart user who understood your checks could roll it back to the closest time to the last time the app was shut down, but at least this would limit them to having access to the content for 7 days of run time. Also, it would take a really dedicated person to keep track of / exploit your checks. Most users would simply try to roll back their clocks to a past date and it would be simple to catch. With this method, make sure you are capturing / storing all times in UTC time, so that time changes don't trigger a false fraud scenario.
Recommendation
Personally, I would use both options if you are OK with the GPS permissions on your app. If available, and given permission by the user, use the last known location to get the time. If that isn't available, or if the user has removed the permissions, use a local store of run date/times and durations as a fall back.
We're building an App using Ionic/cordova that will need to run on Android, iOS and Windows 10 Mobile.
The goal is to register start and stop events, we'll need the exact time and location when this events are registered.
There is a serious concern that the users will modify the timesettings on their phone to send false data.
As long as these events are sent immediately to the server, we can use the server time to validate what the user is sending us. But there is also a requirement to be able to work when offline.
Our first thought was to use the GPS time. In cordova the position object has a timestamp.
https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-geolocation/
But after further reading, here and here, that this isn't necessarily the time of the GPS server but also just the local time. I've read about work arounds using the uptime of the device, but this won't work as soon as there is a reboot. But most of these conversations are a few years old.
For now we think the simples approach will be to flag events that are sent offline as 'suspicious'.
Is there any other way to accurately determine the time when you're offline without risk that the user tampered with it?
Haven't tried it myself,but what about getting the time from the Network Provider, as said in this SO: I want to get time from GSM network
long networkTS = locMan.getLastKnownLocation(LocationManager.NETWORK_PROVIDER).getTime();
Time returned by getLastKnowLocation could be old if you want current
time use
locMan.requestSingleUpdate() and pass the network provider
Though, this may not work in iOS or Windows.
My app will have a 'clock in' in the listview. As a user will click that item it will grab the time/date from the phone itself and send that data out to the server. I prefer doing this over using server time since if they dont have a signal/reception they wont be able to clock in. I would like to add a password security to the time/date settings itself so the user wont be able to take advantage of changing the time when clocking in. How can I make that happen?
Thanks
I don't think you can do that, but you can cross-check the time.
When you "clock in" also open /proc/uptime as a text file and read the value there. I believe it is in seconds. When you clock out, re-read the value and use the difference as a cross-check. If a server is also available, check the time from the server too (or report the clocking in immediately)
If the phone crashes or is powered off in between, the difference in uptime could be less than what you've recorded via the ordinary clock. In that case, the difference in uptime might be less than the ordinary clock (likely it will be negative) so if your clock-in was done without access to network time your software may have to have a way to report that particular result as unverified, and track the number of unverifieds per user to flag for human review if it becomes excessive.
A user could conceivably compile and install a kernel that lies about uptime, but that person could probably get around most of the other things you would do, too.
I would suggest to just send message to server "user X wants to clock in". And server will use its local time for "clocking in". This way you will completely ignore device's time, and have more control over your infrastructure.
In general, if you want something to be as secure as possible, don't do this on the client side (unless you absolutely have to). And in this case user may gain root on his device and use some command line magic to fool you server with fake date/time. Its not that hard. And you just won't be able to predict all the smart workarounds of you "time protection".
You could set up a service to run every minute (or so) that checks the time. If the time is not ~1 minute after the last check then it may have been changed. You should confirm with the server at this point to make sure the discrepancy wasn't caused by rebooting the phone.
If you find that the time was changed, you can change it back or log this with your main application and flag the "user" for disciplinary actions.