I am building a web app which offers users certain unlockable feature at certain locations. And I just realized how easy it is to spoof GPS location. Chrome dev tools even offers GeoLocation custom location override setting under sensors. How can I set effective checks for similar hacks?
UPDATE:
Chrome dev tools Geolocation override outputs accuracy of 150m thus IF I set a threshold i.e 40m accuracy (reject all data with accuracy greater than 40m). then that can account for the easy chrome dev tool hack (which is great for testing)
It's not possible to prevent users from spoofing their location. Even if you could prevent it in the client software (and to be clear, you can't), the user could feed a location in via an external GPS (or simply a serial port driver with spoofed location data).
What you can do is watch for signs of this spoofing. You could put in thresholds for location changes and what not. If someone suddenly appears to move further than is reasonable, you could flag the data as suspicious. This isn't ideal though, as sometimes immediate location updates happen. (Suppose your device was in airplane mode before you took off from one city, and then updated as soon as you took it out of airplane mode. For a short time, the phone thinks it is in one place, and then is immediately transported to the correct place.)
In the end, there's nothing you can reliably do about it, in a generic sense.
Related
I'm working on a project where the user's location is needed. The implementation seems to be working correctly, the user gets a prompt to allow sharing their location and the coordinates are received.
The problem is that those coordinates seem to wildly change based on the device or browser. Three different browsers in the same device provide 3 different coordinates, and not just with my code, the same happens when testing with other sites that provide geolocation like https://my-current-location.com/
Does this mean that the browsers Geolocation API can't be trusted? Is there a better way of obtaining a user's location that's more reliable?
I've tried working with server-side location (IP) and the results were also as bad, at least for the part of the world where this needs to work.
In an HTML5 web app, I'm building a feature that relies on client-to-client communication (with pusher). It's made of PHP on the server-side and Javascript with Vue on the client side.
The typical scenario is: a window popup is opened, and from there it communicates directly with some other windows opened into any another browser on the same computer. Let's say you have 2 browsers installed, you open the web app popup with Firefox and it communicates with its web app sister page you did open previously into Chrome.
The only (half-)way we have found so far is to use the public IP address to build a private channel named with the IP address… It's basic and efficient.
However, if there is more than 1 computer connected to the same router, all of them will share the same public IP, and that's where things become difficult!
A solution could be to add the computer's local IP to the channel name (that was already built with the public IP), but despite a few nice workarounds I found to get this info from an initiated RTC Connection, this looks quite unreliable and often goes against browsers privacy rules…
Obviously, I cannot use session information with PHP on the server-side, nor cookies / local storage on the client-side, as all those solutions are tightly coupled with the browser itself (thank God Chrome won't share its cookies with Firefox on your computer). Those solutions would be perfect (and no need for a pusher) if we were using 1 single browser, but we need to handle multiple browsers on the same machine.
That's where I'm wondering if anyone would have already dealt with this design challenge and shared some tips, it would be awesome! Thanks for reading so far!
You can check the user agent of the browser.
You can check a combination of the request headers coming from different browsers.
You can explicitly throw and catch an error in the user's browser and send it in the request header/body to determine what browser they're using.
You can do canvas drawings to see the user's GPU/CPU information (since you're already using html5 that's a bonus).
You can directly use webgl to do the same with perhaps different metrics (since canvas uses webgl anyways).
You can check their typing speed or even build up a profile of their vocabulary and use of language.
If you ask for permissions you can see all of their connected media devices like headphones, even just asking for audio permissions will show you all of them.
You can benchmark their CPU with things like the time it takes to find primes or encrypt a key.
You can use audio fingerprinting, which is almost as unique as your voice, since each browser and CPU architecture slightly differ in the digital pattern and oscillations created from audio, which can be captured.
You can check their window size and screen size and screen resolution.
There's probably even more I didn't think of now, you can also use any of them in combination to fingerprint a device.
For more information research browser sniffing and digital fingerprinting. What's more is that you can uniquely identify the user across their own browsers on the same computer and also different users from different devices using a combination of browser sniffing/digital fingerprinting.
In your specific case you can't use all the browser sniffing techniques but you can still use some of them, like the user agent since it will still give you the user device information even if they're using a different browser.
The idea with digital fingerprinting is that you want to build up a probability high enough that you can be fairly certain it's the same user, you can't ever be truly sure, but sure enough. Something like screen size doesn't mean much by itself, there's millions of devices using i.e. a size 1600 screen, however consider the following hypothetical example:
User's device has screen size of 1600, that's i.e. ~1/8 users.
User's device took 20ms to encrypt a 4096 key, that's i.e. ~1/8 users.
User's device took 40ms to draw a canvas image, that's i.e. 1/8 users.
Now you already have a 8 * 8 * 8 = 1/512 probability of knowing what user it is and that value goes up way higher very quickly, based on 3 fundamentally unidentifiable things.
However it should be noted that using any browser sniffing or digital finger printing techniques like above fall under privacy regulations (at least in some countries). A lot of things like the user agent is being deprecated and if you do things like this on a site you'll get into trouble with things like GDPR. I believe you can get around that if you explicitly ask the user for their permission and let them know that i.e. their browser is being fingerprinted. However you have to be careful because doing this can get you in trouble if it's malicious, doing things like this without a user's knowledge is unethical.
In Chrome DevTools you have the ability to spoof a location to return to the Geolocation API, by putting a lat/lon into the Sensors tab. This works well, but there doesn't seem to be a way to spoof the heading or speed or any of the other properties that are returned.
This makes testing anything that makes use of heading/speed rather difficult, as it just returns null when you override from DevTools. At the moment I am having to load my localhost application onto a real device, then unplug it, take it outside and wander round the streets, which is a little tiresome.
Does anyone know of a way to emulate the heading/speed properties without leaving my seat, either using other dev tools, a plugin or a code snippet.
I was wondering for my website, how accurate is the GeoLocation attribute of the navigator object in desktop web browsers? I guess on a mobile web browser this simply activates a GPS device so therefore is based on GPS signal at that time. However what about on a desktop? Does it have some means of determining its location and to what accuracy?
According to the spec:
Under the interface section:
The Geolocation object is used by scripts to programmatically determine the location information associated with the hosting device. The location information is acquired by applying a user-agent specific algorithm, creating a Position object, and populating that object with appropriate data accordingly.
Under the requirements section
6.2.8 The Geolocation API must be agnostic to the underlying sources of location information.
TL;DR: Depends on the browser's implementation. This could mean that it could use anything available on the device. It may even be possible to have "Mobile Provider" and "GPS" on a PC, since there are devices like Nokia Booklet 3G that has GPS and can be inserted a SIM.
I am using the geolocation functionality to track user's locations with javascript. More specifically, I am using navigator.geolocation.watchPosition. My site works fine. When I visit my site on my Android device it prompts if I would like to allow the site to track my location. I tap allow (as well as remember my preference).
After success with that I turned off location services on my phone and went back to the site. It didn't prompt me for permission again (since I told it to remember my preference last time but it didn't prompt me to turn on my location services either. Needless to say at that point my site never got any geolocation data from the browser.
My question: Is there some way to prompt the user to turn on their location services programatically? If I had not saved my security preference and it prompted me to allow again would it have turned on or asked me to turn on location services? I would hate to have to tell the user they need to go into their cell phone's preferences to enable it.
It's browser specific or to be more exact - application specific. What you could do is wait e.g. half a minute or a minute for the location and if it is not available show a warning to the user.