How to avoid getting your location-based app spoofed?

When you are developing your new location-aware app., it is important to understand that people can spoof their GPS location and fraudulently activate some of your app features.

Because we have received quite a few questions about location spoofing, we’ve decided to write a blog post and explain a few ways to avoid your app to get spoofed.

First of all, you need to understand that none of the tracking methods are particularly easy to spoof. It can be done but it is simply outside of the reach of the average user as it generally requires either a modified device (physically – rooted or programmatically – emulator) or some external gear.

Android Devices

To enable the Developer Mode (these steps are for KitKat), tap on Settings > About > Software information > More.

You should see a short list of items that includes “Build number“. Now, tap “Build number” seven times and your phone will flash a message: “You are now a developer.” – Yes, you are :-) !

Now, if you go back to Settings, you should see Developer options near the bottom of the menu. Tap it and you’ll see a message pop up like “These settings are for development and testing purposes. Making changes may affect your phone’s performance. Please proceed with caution.” . No worries, everything is gonna be alright. Go into Developer Settings and enable Mock Locations. Then you canuse one of the fake GPS apps available in the Google Play Store: click here to check them out.

You have built an awesome location-aware app and you’d like to prevent your users to spoof your locations (for instance, your app unlocks features only when users are at specific locations), here what you can do:

1. You could check if the device enables Mock Locations and might be using a fake GPS app:

//returns true if mock location enabled, false if not enabled.
public static boolean isMockLocationOn(Context context) { 
  if (Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION).equals("0")) 
    return false; 
  else 
    return true; 
}

2. You can check whether there are any other apps in the device which are using android.permission.ACCESS_MOCK_LOCATION

 /** Checks if the device is rooted.   
  * @return <code>true</code> if the device is rooted, <code>false</code> otherwise.
  */
 public static boolean isDeviceRooted() {
    // Get the build tags info - See note below to know more about it
    String buildTags = android.os.Build.TAGS;
    if (buildTags != null && buildTags.contains("test-keys")) {
      return true; 
    }
    // Check if Superuser.apk is present
    try {
      File file = new File("/system/app/Superuser.apk");
      if (file.exists()) {
        return true;
      }
    } catch (Exception e1) {
      // ignore
    }
    // try executing commands as a superUser
    return canExecuteCommand("/system/xbin/which su") || canExecuteCommand("/system/bin/which su") || canExecuteCommand("which su");
 }

// Executes the specified string command in a separate process
private static boolean canExecuteCommand(String command) {
  boolean executedSuccesfully;
  try {
    Runtime.getRuntime().exec(command);
    executedSuccesfully = true;
  } catch (Exception e) {
    executedSuccesfully = false;
  }
   return executedSuccesfully;
  }

Note: “release-keys” and “test-keys” has to do with how the kernel is signed when it is compiled. “release-keys“ means it was signed with an official key from an official developer. “test-keys“s means it was signed with a key generated by a third-party developer.

If both above functions first and second are true , then there are most chances that location may be spoofed or fake!

3. Spoofing can be avoided by using Location Manager’s API and removeTestProvider() method (Removes the mock location provider with the given name) as shown below:

LocationManager lm = (LocationManager) getSystemService(LOCATION_SERVICE);
try {
          Log.d(TAG ,"Removing Test providers")
          lm.removeTestProvider(LocationManager.GPS_PROVIDER);
     } catch (IllegalArgumentException error) {
          Log.d(TAG,"Got exception in removing test provider");
     }
 lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 0, locationListener);

You can remove the test provider before requesting the location updates from both providers: Network and GPS.

4. You can try to use a range of anti-spoofing measures using a list of the below measures:

  • Check the general location of cell towers (very low battery drain): you could check to see if the current cell tower matches the location given and apply a margin error
  • Use speed of the device: maximum and minimum speed limits may apply.
  • Corroborating measures: cross referencing WI-FI SSID’s received with your location database and validate IP address of your mobile users.

iOS Devices

It is a bit tricky to know when your users are spoofing their locations for iOS devices. There are multiple ways to spoof a location: Example 1Example 2.

One thing you might want to try is to detect when a device is jailbroken. Once a device is jailbroken, a lot of other files and applications are installed on the device. Checking for these files in the filesystem can help us identify whether the device is jailbroken or not.

Let’s see how to do it:

+(BOOL)isJailbroken{
if ([[NSFileManager defaultManager] fileExistsAtPath:@"/Applications/Cydia.app"]){
  return YES;
}else if([[NSFileManager defaultManager] fileExistsAtPath:@"/Library/MobileSubstrate/MobileSubstrate.dylib"]){
  return YES;
}else if([[NSFileManager defaultManager] fileExistsAtPath:@"/bin/bash"]){
  return YES;
}else if([[NSFileManager defaultManager] fileExistsAtPath:@"/usr/sbin/sshd"]){
  return YES;
}else if([[NSFileManager defaultManager] fileExistsAtPath:@"/etc/apt"]){
  return YES;
}
return NO;
}

Checking for these files in the A user running a jailbroken device can install your app in the /Applications folder and give it root privileges. You can add a check to see whether you can modify a file outside the application bundle (sandobxing rules)

NSError *error;
NSString *stringToBeWritten = @"This is an anti-spoofing test.";
[stringToBeWritten writeToFile:@"/private/jailbreak.txt" atomically:YES
encoding:NSUTF8StringEncoding error:&amp;error];
if(error==nil){
   //Device is jailbroken
   return YES;
} else {
   //Device is not jailbroken
   [[NSFileManager defaultManager] removeItemAtPath:@"/private/jailbreak.txt" error:nil];
} 

Most of the devices that are jailbroken have Cydia installed on them, and even if the hacker can change the location of the Cydia app, he most probably won’t change the URL scheme with which the Cydia app is registered. If calling the Cydia’s URL scheme (cydia://) from your application gives a success, you can be sure that the device is jailbroken.

if([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"cydia://package/com.example.package"]]){
  //Device is jailbroken
}

Note: Don’t forget to add the following line to make sure that this code does not execute if you are testing your application on a simulator.

#if !(TARGET_IPHONE_SIMULATOR)

There are a few other ways to check if the device is jailbroken but added the above checks  will help you prevent location spoofing in most cases but bear in mind that a good hacker will always find a way to bypass these checks…

Source:

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>