2

I'm trying to build a piece of PHP script that will uniquely identify a mobile device using the HTTP request sent to the server when the page is called.

I know that there is UNIQUE_ID in $_SERVER, however that is a random string generated unique to each request, not each device. So far, it looks like the HTTP request is set up to prevent exactly what I'm doing, to stop servers from tracking users without their consent.

The problem is, I need a way to identify the device so that it loads the correct kiosk display which is stored in my database. IP address is not feasible, because I will set the device up in my office, then ship it to its destination, in which case the IP will change.

I could use a cookie and UNIQUE_ID upon first time loading of the page, but if the history gets deleted, the device becomes disassociated with its previous setup.

I thought about creating a random string of my own, so that if the setup gets wiped, the user could simply input the string to re-associate it, but the whole idea behind this is that I'm trying to avoid user input altogether.

Another option is using SureFox to manage my devices remotely, but I'm trying to keep as much control as I can.

Any ideas on how I could uniquely identify a device in PHP each time it requests pages from the server?

Dexter
  • 795
  • 2
  • 13
  • 27
  • Do you control "device" (at least in sense you can modify browser settings)? – Alexei Levenkov Feb 20 '16 at 06:20
  • Yes, I set the device up, put it into kiosk mode, and ship it. If there are any problems, the user will call me. – Dexter Feb 20 '16 at 06:22
  • What kind(s) of device(s) are we talking about? – VolkerK Feb 20 '16 at 06:59
  • @VolkerK I'm trying to decide between the iPad and some Android tablet, to be used as a Kiosk – Dexter Feb 20 '16 at 07:00
  • And what about simply letting the user log in -> set cookie. If the system is wiped the user has to log in again. (This more of a question, not an answer: "What hinders you from doing that?") – VolkerK Feb 20 '16 at 07:18
  • @VolkerK, I have considered cookies, but I am trying to avoid them. Control over the kiosk setup is a priority for me because a) the labor of setting these up is a paid service I'm going to provide, b) limiting user interaction is a must (don't want people screwing with them that aren't authorized), and c) The people I'm going to do this for are mostly tech illiterate. – Dexter Feb 20 '16 at 07:22
  • Ok, i have to accept that .....but (of course there's a "but" ;-)) : The users are so illiterate they can't type "Mike8912" into a (html) text field, presumably only once? They aren't using gmail or _any other_ service that requires a log in? And you're setting up the device; so you can allow persistent cookies with arbitrary expiration dates. It sounds more reliable to me than fiddling with the os/browser/plugins - admittingly without taxing my brain too much ;-); even _if_ the device breaks down, the user _can_ (temporarily) switch to another computer if it is important/urgent. – VolkerK Feb 20 '16 at 07:31
  • @VolkerK The main reason I'm trying to avoid having the user login is that I have had a kiosk running in my store for several years, and any time the app required a login, there were emails sent, phone calls made, and detective-work done, because the store manager could never find his password. THAT is what worries me--my own personal experience watching him fret, and hearing the sighs of frustration from the Rep haha – Dexter Feb 20 '16 at 07:37

2 Answers2

2

The only piece of information that can be persisted over history resets is user-agent string. That works if you have control over device (as in your case) and can adjust browser's configuration to use custom user-agent string (way of setting it depends on browser).

There is no other information that browser by itself provides that can uniquely identify device (cookies can be reset/lost, IP changes, no no other headers are automatically send by browser).

Alternative approach could be to have custom link/command that launches browser to include device identification into URL as query string. More extreme - custom local proxy (i.e. can model with Fiddler) that adds custom headers to all requests.

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
  • I was Googling around and discovered the `.mobileconfig` file for Apple. I may be able to create my own unique identifier that I can install before the device leaves and not have to worry about the user deleting it by clearing history. My only worry would be if a device was reset to factory settings, but I believe I can prevent that. – Dexter Feb 20 '16 at 06:29
  • @Dexter you should create an answer with your chosen solution – Toby Allen Feb 20 '16 at 07:48
  • @TobyAllen I plan to, but I'm still working on the details. I wanted to show exactly how to get the UDID from an Apple device using a `.mobileconfig` file, since the information is all over the place. It may take me until tomorrow to get it all together though. – Dexter Feb 20 '16 at 07:50
1

Well, after some biting and gnashing of teeth, I've got this figured out, thanks to this post, this post, and this post.

I created a file called UDID_request.mobileconfig. It looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>PayloadContent</key>
        <dict>
            <key>URL</key>
            <string>http://kiosk.mydomain.com/setup/index.php</string>
            <key>DeviceAttributes</key>
            <array>
                <string>UDID</string>
                <string>IMEI</string>
                <string>ICCID</string>
                <string>VERSION</string>
                <string>PRODUCT</string>
            </array>
        </dict>
        <key>PayloadOrganization</key>
        <string>mydomain.com</string>
        <key>PayloadDisplayName</key>
        <string>Profile Service</string>
        <key>PayloadVersion</key>
        <integer>1</integer>
        <key>PayloadUUID</key>
        <string>9CF421B3-9853-4454-BC8A-982CBD3C907C</string>
        <key>PayloadIdentifier</key>
        <string>com.mydomain.kiosk.profile-service</string>
        <key>PayloadDescription</key>
        <string>This temporary profile will be used to find and display your current device's UDID.</string>
        <key>PayloadType</key>
        <string>Profile Service</string>
    </dict>
</plist>

Next, I created /setup/index.php:

<?php
$data = file_get_contents("php://input");
file_put_contents("udidlog.txt", $data);
header('Location: http://kiosk.mydomain.com', true, 301);
?>

Next, I pointed my iPad's Safari browser to the .mobileconfig file I created earlier. It took my to a Profile Certificate installation window. I hit install, confirmed installing an unsigned certificate, and it sent a response to /setup/index.php, which copied the response to my udidlog.txt file and then redirected to my kiosk homepage.

It wasn't easy. It was, in the words of one of the posts, finicky. The responses weren't going across until I had my redirects right, etc.

The response I get back is jumbled with certificate signing, but the important XML part is in plain text, so I extracted the XML using:

function extract_xml_from_plist($data) {
    $sTag = "<?xml";
    $eTag = "</plist>";
    $startsAt = strpos($data, $sTag);
    $endsAt = strpos($data, $eTag, $startsAt) + strlen($eTag);
    $result = substr($data, $startsAt, $endsAt - $startsAt);
    return new SimpleXMLElement($result);
}

$xml = extract_xml_from_plist($file);

Here's the XML from the response I got back:

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>ICCID</key>
    <string>8901 4104 2541 8901 7521</string>
    <key>IMEI</key>
    <string>01 266900 647352 2</string>
    <key>PRODUCT</key>
    <string>iPad2,2</string>
    <key>UDID</key>
    <string>591f30d41d0bd28597ad962491f1570ddbde4a8a</string>
    <key>VERSION</key>
    <string>9J2</string>
</dict>
</plist>

Now, using $xml->dict->key[n] and $xml->dict->key[n], I created an associative array of the device attributes returned by the device at my request. I now have a unique identifier that will always be the same for that device, and I can use that to create a sort of login cookie. When the cookie gets wiped? Just redirect and get the UDID again! No logins, no passwords, all setup in my database before it leaves my building. Fun stuff.

As for Android, it appears MDM is much less centralized. There are plenty of MDM Servers out there, but I think the easier solution would be to use an already developed kiosk management program like SureFox, rather than reinvent the wheel. While this doesn't exactly answer my question as far as Android UDID is concerned, it does work for my solution, and with the money I'd save on buying android tablets instead of iPads, it's more than worth paying for multiple licenses.

Community
  • 1
  • 1
Dexter
  • 795
  • 2
  • 13
  • 27
  • Please make sure to update your question too so it is clear that you are looking for iPad/iPhone specific solution. Otherwise your own answer is not an answer. (Can't vote on your answer as I have no idea if that is the right way - there are still couple people out there without Apple devices, sorry about that). – Alexei Levenkov Feb 20 '16 at 18:28
  • @AlexeiLevenkov I plan to work on a way for android tonight too, which I will also post, since I still have another day before I can select an answer. Currently there's no Android analogue for Apple's sending .mobileconfig files, but I haven't even explored Google sign in and Android profile controls yet. With the cost reduction of android tablets, I may just purchase the SureFox Pro license and be done with it. – Dexter Feb 20 '16 at 19:24
  • After some testing, I also need to add how to prevent Apple device from responding with a bunch of either binary or hex, because it seems to be screwing with the PHP script that traverses the XML – Dexter Feb 20 '16 at 19:32
  • @Dexter There is a way to uniquely identify tablet while using SureFox from your server, do reach us at techsupport@42gears.com in case you need any assistance. – RPB Jul 12 '16 at 06:12
  • 1
    @RinkalBhanderi thanks Rinkal, I actually found SureFox to be the best solution after all. I bought the licenses, read the documentation and set it up, and it's working perfectly, exactly as I needed. – Dexter Jul 13 '16 at 21:40