Uniquely identify the device in iOS - ios

I am developing a corporate application on the iPad for a certain business requirement.
This app is meant to use in a specific number of devices which is predefined by the admin.
But I also need the application to reject any login requests even if it is from an authorised user,when he or she is using a device which is not defined by the admin.
Edits:
Say I have 2 devices and I have my credentials to login to the app, And my need is, to restrict the login from the devices which is not mine.
For that I have to identify whether the login request is comes from my device or not.
Previously we could use device UDID to do this, but now it is deprecated.
Can any one please suggest a method to implement this ?

try this. for more info check UIDevice
// IOS 6+
NSString *uniqueIdentifier = [[NSString alloc] initWithString:[[[UIDevice currentDevice] identifierForVendor] UUIDString]];

You can use iCloud over here because UUID has been deprecated and vendorId is uniqe but might be change if you uninstall the app and install it agian,
So I would suggest iCloud will be safer, what you cna do is at the time of application launch you can generate one token which is unique and save it to your iCloud data storage along with user credentials,
So from the next time onwards when user will try to login you can check it with iCloud.

How about using Apple's enterprise distribution system? That will allow you to deploy the app to a corporation, and have tight access control.
https://developer.apple.com/programs/ios/enterprise/

Just Trick:
You can Implement APNS code to your Project and Get Device Token.
The Device Token is Unique One. But The user Must Allow the APNS.
Note: APNS Device Token is changed to Following reasons.
Change of Bundle id.
Change of Development Mode(Sandbox/Production)

I have implemented a solution for exactly your problem, The best solution (and Apples recommended route) is to create a UUID unique to your App like this:
NSString *uuidString = nil;
CFUUIDRef uuid = CFUUIDCreate(NULL);
if (uuid) {
uuidString = (NSString *)CFBridgingRelease(CFUUIDCreateString(NULL, uuid));
CFRelease(uuid);
}
Then, and this is the key, you can store that to the iOS keychain (Handy classes here: https://github.com/lukef/IXKeychain) and values in the iOS keychain are NOT removed when the user uninstalls the App, so you can persist your own UUID through App installs which is a key part of managing a specific number of devices against a user account.

This method will return a string for every device. Since it is gonna change every time for single device
so we are storing it in a keychain and can refer it whenever we need it.
+ (NSString *) uniqueDeviceIdentifier
{
NSString *deviceUUID = [[SGKeyChain defaultKeyChain] stringForKey:#"uniqueId"];
if (!deviceUUID) {
if (!deviceUUID.length) {
NSString *deviceUUID = #"";
CFUUIDRef uuidRef = CFUUIDCreate(NULL);
CFStringRef uuidStringRef = CFUUIDCreateString(NULL, uuidRef);
CFRelease(uuidRef);
deviceUUID = [NSString stringWithFormat:#"%#",[NSString stringWithString:(__bridge_transfer NSString *)uuidStringRef]];
[[SGKeyChain defaultKeyChain] setObject:deviceUUID forKey:#"uniqueId" accessibleAttribute:kSecAttrAccessibleAlways];
}
}
return deviceUUID;
}
yo can refer to this repository... https://github.com/sgup77/SGKeyChainWrapper for SGKeyChain implementation

Ok I will share the approach that we follow for a B2B enterprise app.
.
Every User has login Id and Password.
1. So user register his device with Server using deviceReg API which takes clientDeviceId as param(client generated uuid) along with username and pass.
2. Server returns a server generated unique identifier to be used by application on that particular device.
Conclude - in this way you can restrict the user with a certain device.
You can use below method to generate deviceSpecific client UUID
- (NSString *)getUuid
{
CFUUIDRef uuidRef = CFUUIDCreate(NULL);
CFStringRef uuidStringRef = CFUUIDCreateString(NULL, uuidRef);
CFRelease(uuidRef);
NSString *uuid = [NSString stringWithString:(__bridge NSString *)uuidStringRef];
CFRelease(uuidStringRef);
return uuid;
}
Please note:
I remove the explanation about using AuthKey, AccessToken and others which we use for security purpose as you do not use any auth server.
I hope it helps.
Update 1.
Since you are having an enterprise application so i am sure you would be having atleast the user e-mail ids.
So the account manager should than 1st send a email with one time token to all active accounts.
This token can be requested by the application while registering the device and send to server for validation.
Also the server invalidates the token once used to avoid misuge.
There should be a migrAtion api which uses the server generated device id and a migration token if user migrates the device.

Related

Unique Identification of iOS device

I was using Mac address for unique identification of the iOS device, but from iOS7 the system always returns 02:00:00:00:00:00 value. I had searched three options for the mentioned issue:
Vendor identification
Advertising identification
Getting serial number using IOUnit framework
Since the IOUnitFramework is not approved by appstore, cant use it in my application. And the vendor identification and advertising identification return very long values.
Is there any other possible way to uniquely identify the ios device?
Thanks in advance
Storing a unique identifier in keychain is another option. But we can't access the keychain directly from our ios device.So is there any other alternative way for unique identification of the device?
No, Apple does not allow you to uniquely identify devices any more. This has to do with the user privacy. Since you are not identifying the user but a device.
Also don't use the ASIdentifierManager for identifying device, Apple is now reject apps that use this to identify device. The ASIdentifierManager is only to be used for advertisement purposes.
The only option left is either the the [[UIDevice currentDevice] identifierForVendor] or save your own custom create ID to the keychain.
Saving to your own create id to the keychain will make sure that if the user deletes the app en reinstalls it later you can still access this value.
You can use UDID of the device by which you can uniquely identify iPhone device
Create UIID from this method
- (NSString *)createUUID
{
CFUUIDRef theUUID = CFUUIDCreate(NULL);
CFStringRef string = CFUUIDCreateString(NULL, theUUID);
CFRelease(theUUID);
[[NSUserDefaults standardUserDefaults] setObject:(__bridge NSString *)string forKey:#"UUID"];
[[NSUSerDefaults standardUserDefaults] synchronize];
return (__bridge NSString *)string;
}
Use this where you need the device UDID
- (NSString*)UUID
{
return [[NSUserDefaults standardUserDefaults] ObjectForKey:#"UUID"];
}
You might check on this link and this link. It shows you multiple ways to identify your iOS device. They are a little outdated, but identifierForVendor and advertisingIdentifier still works.
Advertising identifier is mainly used for advertising purpose, but Apple is encouraging using this identifier for any needs.
advertisingIdentifier is part of the new AdSupport.framework. The ASIdentifierManager singleton exposes the method advertisingIdentifier and calling that returns an instance of the NSUUID class.
NSString *adId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
Identifier for vendor also return an UUID string :
NSString *idfv = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
There are a lot of ways for to get an unique identifier. You can get identifierForVendor as some guys recommended you or create an UUID as mokujin recommended you. Even there are external sources libraries like SecureUDID, OpenUDID... but all these has the same problem, if you remove your app and reinstall, you will get different identifier.
I have been working in a big company where they used MDM (Mobile Iron) which give you the posibility of to get the real UDID. I think you are not using MDM in your project so I recommend you to use one of the choice recommended here for me and others users and save it in your keychain. After of this, you should to check if you have this value keep in your keychain, for using it, if not, you should to get it and keep it.
Don´t save it in your NSUserDefaults because if you delete your app, your info kept there will be deleted.
For use your keychain I recommend you to use this class from Apple KeychainItemWrapper
Apple kills the way of tracking application, though we can track application using following ids
Identifier for vendor
NSUUID
CFUUID
But this device ids will reset if you factory reset your phone.
You will get detail description over here unique device identification in iOS

Unique Identifier should not change with iOS version change

I'm developing an application which is using device unique identifier to register device with server.
I am using MacAddress to get unique identifier of device, but in iOS7 it will return same(static for all device).
I found other alternate as
NSUUID *vendorId = [[UIDevice currentDevice] identifierForVendor];
But that will change as iOS device changed.
So can anyone suggest me some unique identifier which will not change if iOS version change it should be same for all iOS version (iOS7, iOS6).
There is a simple answer: It is not possible. Here you have an overview over the identifiers: The Developer’s Guide to Unique Identifiers
Apple is not allowing to use the Device's UDID to identify the users. So you can do it in other way.
Instead of sending the UDID to the server, create a unique Id on the server and put that ID in the application to recognize the user. In this way, you will not break the Apple's guidelines and the problem of varying the iOS versions also get resolved with this.
Just store the UUID into the keychain.
sskeychain refers to https://github.com/samsoffes/sskeychain
code as following^^
NSString *identifier = [SSKeychain passwordForService:kSSToolkitTestsServiceName account:kSSToolkitTestsAccountName];
if (identifier != nil && [identifier length] > 0) {
return identifier;
}
identifier = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
[SSKeychain setPassword:identifier forService:kSSToolkitTestsServiceName account:kSSToolkitTestsAccountName];
return identifier;
Unfortunately Apple disallows application to Uniquely identify a device (AS per them it violates User Privacy).. So you have either left with vendor ID or Advertisement ID.. another thing which you can try is that writing a web service which provides a unique ID to your app on first login and you will store that in in key chain or DB on your device..

Will Apple reject my app if I use the UUID of device?

I am using UUID of current device. I have to send that ID to a server for registering my device.
So I used a bit of code like:
NSString *uuidString = nil;
CFUUIDRef uuid = CFUUIDCreate(NULL);
if (uuid) {
uuidString = (NSString *)CFBridgingRelease(CFUUIDCreateString(NULL, uuid));
CFRelease(uuid);
}
And I am sending that uuidString to the server.
My concern is that Apple will reject my app for using this UUID and sending to a server?
Please give me idea about this, it's Very important for me now.
Why do you think Apple will reject this?
Apple is just not allowing you to identify device any more, by using the UDID or the MAC address of the device.
If you generate a unique number, which you do, then there should be no problem. Just be aware that the UUID you create with the code you posted will be different every time you call the code.
Thus if you use it to track a user then you should generate it once and save the generated UUID somewhere.
Not an anser to the original question I know, but just to point out that there'a NSUUID now so you can avoid all that CF boilerplate.
NSString *uuidString = [[NSUUID UUID] UUIDString];

Can device token of Push Notification be used as a unique identifier?

Problem: using UDID is deprecated - we cannot use it anymore.
There are some solutions on the net: generate GUID and store it in the "safe place", iCloud, IdentifierForVendor starting with iOS6, OpenUID, SecuredID and so on...
Request:
I need to have a unique identifier of the Device to store user data on our server.
Question:
Can I use deviceToken of Push Notification as a unique identifier?
What are the pros and cons of this idea?
(-) user can disable push notifications
(+) unique number
(+) supported in all iOS
This is a terrible idea, the token can change if the user changes device or for some other unknown reason.
The user can have multiple devices
If the user reinstalls the app they can get an other token
It's not 100% that the user will keep the same token.
And most important of all: You are identifying devices not users!
One solution is to generate a UUID and save it in the user keychain where you retrieve it. But this can also be removed if the user clear the device.
You best option is to allow the user to login with an account, which that can create. Then you can combine this with the UUID in the keychain.
You should use identifierForVendor. The deviceToken for push notification is unique, but CAN change.
The token can change if the user reset the device, for unique device identifying you can use the following code
float currentVersion = 6.0;
NSString *udid = nil;
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= currentVersion)
{
//below code is taken from the Apple Sample code, to check you can download the files
https://developer.apple.com/library/ios/releasenotes/StoreKit/IAP_ReceiptValidation
// OR
http://developer.apple.com/library/ios/releasenotes/StoreKit/IAP_ReceiptValidation/VerificationController.zip (line number 319)
udid = [UIDevice currentDevice].identifierForVendor.UUIDString;
}
else
{
//may cause apple rejection
udid = [UIDevice currentDevice].uniqueIdentifier;
//i think we can use the below link for ios5 or below but not sure it may accept or reject
https://github.com/gekitz/UIDevice-with-UniqueIdentifier-for-iOS-5
}
//just saw a link which may help you better and have a look at image
http://www.doubleencore.com/2013/04/unique-identifiers/
can someone suggest the best way to persist the unique id even after reinstall app, delete app or system restart or system boot or factory reset

Programmatically get own phone number in iOS

Is there any way to get own phone number by standard APIs from iPhone SDK?
At the risk of getting negative marks, I want to suggest that the highest ranking solution (currently the first response) violates the latest SDK Agreement as of Nov 5, 2009. Our application was just rejected for using it. Here's the response from Apple:
"For security reasons, iPhone OS restricts an application (including its preferences and data) to a unique location in the file system. This restriction is part of the security feature known as the application's "sandbox." The sandbox is a set of fine-grained controls limiting an application's access to files, preferences, network resources, hardware, and so on."
The device's phone number is not available within your application's container. You will need to revise your application to read only within your directory container and resubmit your binary to iTunes Connect in order for your application to be reconsidered for the App Store.
This was a real disappointment since we wanted to spare the user having to enter their own phone number.
No, there's no legal and reliable way to do this.
If you find a way, it will be disabled in the future, as it has happened with every method before.
Update: capability appears to have been removed by Apple on or around iOS 4
Just to expand on an earlier answer, something like this does it for me:
NSString *num = [[NSUserDefaults standardUserDefaults] stringForKey:#"SBFormattedPhoneNumber"];
Note: This retrieves the "Phone number" that was entered during the iPhone's iTunes activation and can be null or an incorrect value. It's NOT read from the SIM card.
At least that does in 2.1. There are a couple of other interesting keys in NSUserDefaults that may also not last. (This is in my app which uses a UIWebView)
WebKitJavaScriptCanOpenWindowsAutomatically
NSInterfaceStyle
TVOutStatus
WebKitDeveloperExtrasEnabledPreferenceKey
and so on.
Not sure what, if anything, the others do.
Using Private API you can get user phone number on the following way:
extern NSString* CTSettingCopyMyPhoneNumber();
+(NSString *) phoneNumber {
NSString *phone = CTSettingCopyMyPhoneNumber();
return phone;
}
Also include CoreTelephony.framework to your project.
You cannot use iOS APIs alone to capture the phone number (even in a private app with private APIs), as all known methods of doing this have been patched and blocked as of iOS 11. Even if a new exploit is found, Apple has made clear that they will reject any apps from the app store for using private APIs to do this. See #Dylan's answer for details.
However, there is a legal way to capture the phone number without any user data entry. This is similar to what Snapchat does, but easier, as it does not require the user to type in their own phone number.
The idea is to have the app programmatically send a SMS message to a server with the app’s unique installation code. The app can then query the same server to see if it has recently received a SMS message from a device with this unique app installation code. If it has, it can read the phone number that sent it. Here’s a demo video showing the process. As you can see, it works like a charm!
This is not super easy to set up, but it be configured in a few hours at no charge on a free AWS tier with the sample code provided in the tutorial here.
As you probably all ready know if you use the following line of code, your app will be rejected by Apple
NSString *num = [[NSUserDefaults standardUserDefaults] stringForKey:#"SBFormattedPhoneNumber"];
here is a reference
http://ayeapi.blogspot.com/2009/12/sbformatphonenumber-is-lie.html
you can use the following information instead
NSString *phoneName = [[UIDevice currentDevice] name];
NSString *phoneUniqueIdentifier = [[UIDevice currentDevice] uniqueIdentifier];
and so on
#property(nonatomic,readonly,retain) NSString *name; // e.g. "My iPhone"
#property(nonatomic,readonly,retain) NSString *model; // e.g. #"iPhone", #"iPod Touch"
#property(nonatomic,readonly,retain) NSString *localizedModel; // localized version of model
#property(nonatomic,readonly,retain) NSString *systemName; // e.g. #"iPhone OS"
#property(nonatomic,readonly,retain) NSString *systemVersion; // e.g. #"2.0"
#property(nonatomic,readonly) UIDeviceOrientation orientation; // return current device orientation
#property(nonatomic,readonly,retain) NSString *uniqueIdentifier; // a string unique to each device based on various hardware info.
Hope this helps!
To get you phone number you can read a plist file. It will not work on non-jailbroken iDevices:
NSString *commcenter = #"/private/var/wireless/Library/Preferences/com.apple.commcenter.plist";
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:commcenter];
NSString *PhoneNumber = [dict valueForKey:#"PhoneNumber"];
NSLog([NSString stringWithFormat:#"Phone number: %#",PhoneNumber]);
I don't know if Apple allow this but it works on iPhones.
No official API to do it. Using private API you can use following method:
-(NSString*) getMyNumber {
NSLog(#"Open CoreTelephony");
void *lib = dlopen("/Symbols/System/Library/Framework/CoreTelephony.framework/CoreTelephony",RTLD_LAZY);
NSLog(#"Get CTSettingCopyMyPhoneNumber from CoreTelephony");
NSString* (*pCTSettingCopyMyPhoneNumber)() = dlsym(lib, "CTSettingCopyMyPhoneNumber");
NSLog(#"Get CTSettingCopyMyPhoneNumber from CoreTelephony");
if (pCTSettingCopyMyPhoneNumber == nil) {
NSLog(#"pCTSettingCopyMyPhoneNumber is nil");
return nil;
}
NSString* ownPhoneNumber = pCTSettingCopyMyPhoneNumber();
dlclose(lib);
return ownPhoneNumber;
}
It works on iOS 6 without JB and special signing.
As mentioned creker on iOS 7 with JB you need to use entitlements to make it working.
How to do it with entitlements you can find here:
iOS 7: How to get own number via private API?
AppStore will reject it, as it's reaching outside of application container.
Apps should be self-contained in their bundles, and may not read or write data outside the designated container area
Section 2.5.2 :
https://developer.apple.com/app-store/review/guidelines/#software-requirements

Resources