2013 • 41:46
Securing your users’ personal and business information has never been more important and honoring your users’ privacy is paramount. Learn the best and latest techniques for app security and privacy and find out exactly how to use the keychain, data protection, secure transport, and identifier APIs most effectively.
Speaker: Paul Danbold
Unlisted on Apple Developer site
Downloads from Apple
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
Okay, everyone. Time to talk about security and privacy. I'm Paul Danbold, CoreOS Technologies Evangelist, and I'll start by saying, as I think we all know, there's news reports about security and privacy every day, and usually the news reports are scary for most people, but very rarely do you see iOS and your apps mentioned. And we want to keep it that way, and that's what we're going to be talking about, preserving that great reputation we have.
To keep us on track, a couple of checklists for the things we want to talk about. On the security side, we'll be talking about protecting data on the device, protecting data on the wire, so to speak, a little bit about defensive coding. On the privacy front, when we get to that section, we need to talk about identifiers. We need to talk about the mechanisms that arbitrate access to personal data to your apps. And also the care that needs to be taken when you're logging runtime events and other glitches in ways that protect users' privacy.
I want to start though by saying a few sort of high level things. One is that�� On the security side, we always have to remember that security for mobile devices is somewhat different than, say, desktops. You know, mobile devices, they're always on, they move from network to network, and they're more easily lost or stolen, and they're typically loaded with a lot of personal data and often business data. And these are factors that play into design and implementation decisions that we all have to make pretty much every day.
Another thing, look at this picture. Do these kids look like security experts? Well, actually, today, maybe they are, but it's also fair to say that most of the people who are using your apps aren't particularly security-minded. So, you know, we all know that it's important to set a passcode and make it a strong passcode, and we also all know that it's not a good idea to have the same login credentials for multiple web services, you know, etc.
And it's fine, of course, to ask for a name and password, but generally it's futile to, you know, present users with any kind of security alerts, because human nature being what it is, a lot of people will just try to find the quickest way, not necessarily the most secure way to dismiss an alert. All that boils down to the fact that you need to take the most responsibility for protecting any personal or business data that your apps manage, and you need to do it in ways that don't pester the user. In other words, good security is mostly invisible.
And just one other thing that we all need to recognize is that there's no such thing as unbeatable security. So there's always the possibility that bad guys will look for vulnerabilities in your apps. But on our secure platform, if you take the measures that we're going to be talking about, you're not going to be an attractive target for attackers. They're more likely to go after softer targets on other platforms. And quite frankly, I don't have to worry about that.
Let's get into protecting data on the device. The motto here is "Play it safe." This isn't just about finance apps, medical apps, business apps. We see there's no limit to the creative and unexpected ways that users use apps. Really, if there's any possibility, if there's the slightest chance that an NSString, for example, could contain data that would be bad news if lost or stolen, you should protect it.
When I go looking for security vulnerabilities in an app, one of the first things I do is after I get the app on my iPhone or my iPad is hook my phone up to my Mac and I've got some device management and forensic apps. And it's very easy to see all the app's files. I can move them out of its container onto my Mac, maybe run the contents of a file through a decoder if it's not immediately obvious what's in the file. And see if there's anything interesting or potentially lucrative.
And I don't need to be a programmer to do this. These tools are widely available. And the point is, if it's so easy to do it, you need to protect your data. You need to take measures to make sure it's not so easy to get it in apps files and find personal or sensitive data in them.
So that's where data protection comes in. And we've had it since iOS 4 and the iPhone 3GS. So it's by no means is it a new thing, but we need to keep talking about it until everybody uses it. In a nutshell, it's you telling the OS when you want access to your keychain and your files or thinking about it the other way around, it's you telling us when you want us to safely encrypt your data when you no longer need it, when the device gets locked.
It's as strong as a user's passcode, so obviously a good idea for users to have a strong passcode that's going to take a long time to brute force. And without going into too many details, the way it's done is we take the device's unique encryption key, we take a key derived from the user's password, tangle them together, and use that to create a set of class keys to protect keychain items and files.
And class in this case isn't an Objective-C class, it's just an attribute that you hand us to tell us when you want access to keychain items and files or when you want us to throw away the keys. And I think John mentioned it this morning, I'm sure it's been mentioned a couple of times today.
Obviously when a device is unlocked, you need access to your keychain and files. But�� You may need access when the device is locked, and you can also do that with a level of protection. And it's important to understand how to do that, especially if you use the new background execution modes in iOS 7. So we'll get into that in a few minutes. And for you, the best thing about data protection is that it's a no-brainer. It's just about adding a little extra information to API calls like this. So it's a very lightweight task.
Listed here on this slide, the protection classes for the keychain, for the file manager and core data, for NSData. And we also have protection classes for SQLite, only I couldn't fit them in on this slide. It boils down to this: Try to use the most�� the strongest protection class whenever you can. And that means that anything with that strong protection class is going to be safely encrypted within about 10 seconds of the device being locked.
You can also choose an intermediate protection class when you need access to data when the device is locked. So, for example, if you can see here, the second item for the file manager is complete unless open. What that means is the device has to be unlocked to create the file, but subsequently when the device is locked, you can still access the file.
So, let's say you get a background notification, this protection class will let you access such a file with that protection class. And by the way, dot, dot, dot, I hesitate to mention it, there is even a less secure protection class and really there's no good case for using it. So, always go towards the strongest protection class that's going to work for you.
[ Transcript missing ]
Along the same lines, you don't want to compromise protection of your files just because, let's say, you want to use the new NSURL session background transfer service to download more data while the device is locked. So you can use one of the intermediate protection classes. But what you should do when the download is complete and you have this new file, check that the newly downloaded data is okay and if it is okay, then upgrade the protection class of the new file or else merge the downloaded data into a protected file.
On this slide, I'm just going to cover a few things that are also new in iOS 7. So we all like the fact that your contacts, your calendars, and your notes, etc. sync via iCloud and now in iOS 7 you can do the same thing with your keychain items and I'll go through a few details about that on the next slide. It's useful to know that the state restoration archive is now protected when the device is locked. So you don't have to worry that if your app is in the middle of handling some sensitive data that your state restoration archive could be a weak link.
Also, just so you know, newly installed apps are now protected. That is, the documents, library, and temp directories get the strongest protection class when you install apps on iOS 7. But if you've got apps that were on an iOS 6 device and you upgrade from iOS 6 to iOS 7, those apps maintain whatever protection settings they already had.
And one other thing you may have noticed in the project's capability editor, there's now a switch for data protection. So if you turn that on, you get by default the strongest protection class. That is for all your file operations, etc. If the switch isn't on, you get the default for the OS that the app's running on.
And that may not be what you want because default protection for files, etc. wasn't the same in iOS 6 as it is in iOS 7. And of course, this setting the default doesn't get in the way of any explicit declaration of data protection that you make in your code.
So as I mentioned, not only do you get synchronization for iCloud for things like your calendars and your contacts, you can now do this for your keychain items. All the uploads to the iCloud servers use strong network security. Everything's stored encrypted on the iCloud servers. But you don't get this by default. Items without this new KSEC at a synchronizable attribute aren't synchronized by default.
You have to basically go through all your keychain items and decide on an item-by-item basis what should be synchronized. And you need to think through the implications of having an item that is synchronized when you add an item or update it or delete it for things like logins, etc.
The implementation is limited to passwords, so it doesn't apply to other kinds of keychain items like certificates and keys. But passwords as a category not only can be used for real passwords, but they can be used for other things like account names and credit card numbers, all sorts of things like that.
It does work with shared keychain items, items shared amongst your apps if you use the Keychain Access Group entitlement. Just make sure all your apps use the same KSEC access group name. And also, just as you know, anything that can be synchronized across devices, there's a danger that references to that data could become stale. So be careful on that point.
So that was keychain items. Well, as you know, when it comes to synchronizing documents and core data and key value data, you can use iCloud, and if you do that for free, you get secure transmission of all that kind of data to the iCloud servers and storage on them is secure.
And you also, as you know, have an alternative, which is to use your own servers and take responsibility for securely communicating personal data to those servers, and we'll talk about secure networking next. But just to summarize this section, data protection, huge bang for the buck for almost no code on your part. Be careful if you need access to certain keychain items and files when the device is locked. That's where the intermediate protection classes come in.
And also remember that if your app manages personal data, that's all well and good, but it's not necessarily the whole security picture for you. If you have a server, for example, you need to think about protecting that personal data everywhere that data can be, so not just on the device, but also everywhere else it can go.
Secure transport. So it's near the bottom of the iOS network stack. Most of you probably won't be coding directly to the secure transport APIs and more likely you'll use an SURL connection or an SURL session. But it's down in secure transport where the secure networking protocols are implemented. Before I get into these slides, of course, there's no way to do justice to secure networking in a few slides. So I'm just going to cover a few basics and then talk about a couple of things which you may want to get involved with.
We were looking at how easy it is to get at an app's files and it's kind of the same thing for networking. Here's a screenshot from Charles Proxy. It lets you set up your Mac as a man in the middle proxy so you can view HTTP and HTTPS traffic.
When I took this screenshot I was playing with my banking app on my iPhone and fortunately everything you can see here is gobbledygook and that's the way it should be. And the point I want to make here is that you should be using these tools, packet sniffers, protocol analyzers, etc. to make sure everything that you send from your apps and receive from your servers, etc. is indecipherable to anybody who's sniffing at the packets on the network.
There are two basic and essential requirements to secure networking. One is on the wire, what we call on the wire confidentiality, just making sure that the packets you send and receive are indecipherable to the passive attacker, that's the packet sniffer. The other thing is the ability to authenticate the server you want to talk to, to make sure that you're basically immune from man-in-the-middle attacks. And then the server may want to authenticate you. Often that's just asking for a name and password, but sometimes there's more than that. And you need this confidentiality and authentication.
They are separate, you can have one without the other, but do you want both? I'm going to talk about TLS in the coming slides and of course there are other protocols. Just want to make sure that you all use a secure networking protocol that's going to meet your security needs.
Here's TLS in a nutshell, obviously skipping a lot of details to fit on one slide. Maybe I should say TLS stands for transport layer security. You know, 10 years ago, it evolved out of SSL, secure sockets layer. Basically, There's three steps to it. The client needs to do what we call the handshake with the server. That's where we start off. We tell the server what versions of TLS we support, the cipher suites we have, the compression modes we can handle.
And then the server gets back to us and says, "Okay, I want you to use this version of TLS, this crypto, this compression mode." That's all pretty straightforward. It also sends us this chain of certificates and it's very important that on the device, the iOS device, that we check that chain of certificates to make sure the server is truly who it says it is and can be trusted. And that's what we're going to be getting into in a couple of slides.
By this stage, we've got all the ingredients we need to set up a secure networking connection. The client knows the server's public key because it's in the server's certificate. We encrypt a random number with that, send it to the server. The server has its private key, can decrypt it, and we now have this shared secret.
And we can use that for symmetric key encryption to basically make sure that all the packets, all the data sent back and forth between server and client are protected. And the critical piece I want to get back to here is this chain of certificates. And just to put the visual picture on that, you know, if you want to see a certificate chain, the easiest way to do it is go into Safari on the Mac, click on the little lock icon for any HTTPS site, and you'll see the certificate chain going from the server down to what we call a root anchor, which is a certificate that's implicitly trusted by the OS. typically because it's signed by a well-known certificate authority.
Let's say your app talks to your server using HTTPS, for example, and let's say you write your app and let's say somebody else sets up and maintains your server. And, you know, probably when your app gets published and your server's online, everything works just fine. TLS takes care of the authentication and everything's good.
But there's a possibility one day something's going to go wrong and the default server trust evaluation that TLS does for you is going to run into a problem. Now, before I get into what you should do, a couple of things you really must not do. One is have any code in your app to bypass server trust evaluation because then you're running the risk of sending sensitive data, credentials, personal data, business data to an imposter. And the second thing you really shouldn't do is ask the user to make the connect or don't connect decision because, quite frankly, I mean, how is the user going to know what's safe to do or not? So that's really unfair on the user.
In almost all cases, the problem lies on the server side. And so wherever possible, you should fix the server first. But in the real world, quite often you can move faster than the folks who are maintaining your servers. You know, in the case where the server certificate has expired or the server's DNS name no longer matches the DNS name embedded in the server certificate, you know, really get on the phone or call the server folks and get them to fix that kind of problem. But there are a few problems that you can work around in your app in ways which will allow server trust evaluation to happen as they should happen.
If the server, for example, doesn't send a complete certificate chain to you or if the server uses a self-signed cert, you can embed the missing certificate in your app. And that enables you to allow trust evaluation to happen. And so wherever possible, you should fix the server first. But in the real world, quite often you should fix the server certificate in your app.
For many of you, if you're doing any kind of app which has got kind of an extra level of security required, you may want to go further than allowing iOS to take care of server trust evaluation. We have, I think, over 200 root certificates in the OS, but you may want to explicitly require that certain certificates are in the certificate chain received from the server.
And if you want to do this, this is what we call certificate pinning, you can get involved with trust evaluation. Now, I'm not going to go into any details on this, but I do want to point you to at least one sample code project. The Advanced URL Connections sample project, which has actually been around for quite a while, it's a great introduction to the code that you may want to put in your apps to deal with server trust evaluation.
And I'd encourage you to check out that sample code if you want to get into this area of network security. But for time reasons, we need to move on to talk about other things. I just want to say a few words about secure transport and OpenSSL. Probably, I'm guessing, at least a few of you use OpenSSL. It's an open source project.
It's got a lot in common with open transport, sorry, with secure transport. And, you know, I quite often hear developers say, "Oh, I have to use OpenSSL because, you know, maybe they're developing for multiple platforms, or they've just been told to use OpenSSL." I just wanted you to consider this.
You know, secure transport built on top of FIPS 140-2 certified crypto. It's hardware accelerated, and it's highly optimized for our devices. And, of course, if you use our code, you basically get for free all the improvements we make from one OS release to the next, without changing a line of code or revving your apps. Using OpenSSL, you're building a lot more code into your apps.
You're revving your app every time you want to integrate a new distribution. And you're probably spending a lot more time on network security than maybe you'd like to, you know, maybe you want to do other things with that time. So here, just to plug for some fairly new code, if you are considering migrating from OpenSSL to the native code in iOS, do check out the crypto compatibility sample code. It's up on the dev center. It's in the Mac section, but the code applies equally well to iOS.
Before I move on, basically just to plug for using the packet sniffers and protocol analyzers I mentioned a few slides ago. Choose a secure networking protocol and take the time using network packet sniffing tools, etc. to make sure that you can't find any personal sensitive data in your network traffic. If you can't find it, there's a good chance that you're doing the right thing and attackers won't have any luck trying to get at your network traffic either.
I'm going to spend just a few minutes on defensive coding or secure coding. When you hear talks or start to read documents about this stuff, it's usually about buffer overflows and unsafe string formatting and things like that. You know, techniques that attackers have used to insert malware or cause apps to malfunction. And we will look at a few things that you can do.
But let me just start by saying, you know, Apple does most of the heavy lifting here. You know, we've got a secure boot chain. It validates the integrity of the OS stack at Power Up. We only run apps that are code signed in their sandbox with baked-in entitlements to make sure that even a compromised app can't do much damage.
We've got things like ASLR, address-based layout randomization, which makes it impossible to predict where an app's memory is going to be loaded, where an app's pages are going to be loaded into memory. So that guards against memory management attacks. And we've got a whole lot more. Plug here for this iOS security white paper that's up on the Apple website. And it's a good place to get a good understanding of everything we've done to provide you with a secure platform.
But that doesn't mean there's nothing for you to do. So first thing I want to say is use Clang, the static analyzer. I mean, it really does a whole lot of work for you, weeds out exploitable flaws and other bugs in your code. So periodically or frequently use Clang. Any text field that could possibly contain sensitive information, you should protect it, in other words, market a secure text. It's so easy to do, either in code or an interface builder. Secure text is not cached. We disable auto-correction, so take advantage of it.
If you ask anywhere in your app for an account name and password or just a password, you can use the secure text input and the login and password input alert view style methods just to mask what's on screen. As soon as you can, if you've got any object, anything that could contain potentially sensitive data, just purge it after you've used it as soon as you can. Maybe you need to drop down to core foundation or lower to get at the bits, but good practice.
And if you have a show on screen, what you wouldn't want to find in an app snapshot, there are ways of basically hiding key windows to protect that kind of information. We don't let users down version iOS because that would obviously expose security flaws fixed in more recent versions of the OS.
So it may make sense for you to do an OS version check in your app. I could have had more slides talking about other things that are basically unsafe, like storing sensitive data in NS user defaults, etc. And hopefully you've looked at these last few slides and gone, well, I do all these things, and that's great.
But I do need to point out that we have seen cases where developers may be rushing to get their apps published, have skimped on these secure coding practices, and unfortunately found themselves in the headlines. So it is worth the time to basically audit your apps periodically, make sure you're doing these straightforward defensive coding techniques. I'll say just a few words about what a lot of developers are concerned about, which is what happens if my app is not secure. So what happens if my app is running on a compromised device?
First off, word of caution. So tamper detection can be a little tricky, certainly not a trivial task. And what you want to be really careful of is not compromising the stability of your app, avoiding making your day-to-day development and testing complicated, and especially you don't want to do anything that might impact users running your apps on legitimate devices.
You know, code like this is fine except that if an attacker is patched F open, it's not going to work for you. You know, it's very easy to find scores of what are called jailbreak detection code snippets. Most of them try to do things that are blocked by sandboxing.
And I'm not saying don't do these things. You can litter little bits of code like this through your apps. You know, just putting them in one place isn't going to work, of course. By all means, do this carefully. You will frustrate an attacker. But you have to accept that a skilled attacker with enough patience will probably overcome most of these kind of checks. And that's why we don't have an API to tell you if you're running on a compromised device because that would be the first API attackers would hijack.
Before I move on to privacy, just want to say it's worth the time. Make sure you're using data protection, that your networking is secure, that you're using defensive coding. If you do all these things and repeatedly ask yourself, are you doing all these things correctly, you'll be in good shape.
Now on the privacy front, you've seen us in successive iOS releases giving the user more and more control, deciding on a per app basis who gets access to their personal data and device features. You've also seen us deprecate and remove mechanisms that enable apps to track devices and users.
And there's a part for you to play. And the first thing I want to say is that you should all want to have a reputation as developers who take privacy seriously. And you should also make efforts to make it easy for users to find out what you do with the personal data that your apps manage.
Few words about identifiers, but actually this section should be old news for all of you. No more long-lived identifiers. It's all about purpose-scoped identifiers. We rolled out the app, the vendor, and the advertising ID over a year ago. And of course, as I'm sure you all know, we deprecated the unique identifier API. And now in iOS 7, it's completely gone. Also, get host UUID is gone.
You need to use these identifiers in the way for which they were designed. You need to pay attention to how they behave. You know, they're always backed up, but they don't last forever. In most cases, the vendor ID replaces the old unique identifier or the old UUID. And you need to be careful, for example, with the advertising ID. Remember, the user can reset it at any time. So pay attention to the way these�� to the purpose for which these identifiers were implemented. Use them. And you obviously know by now you need to get away from the old UUID.
We also cranked up privacy protection in a few other ways, which I'll list on this slide. You know, the MAC address. Well, we couldn't deprecate syscontrol and iOctal because they're used for other purposes, but we don't want the MAC address being used as a device identifier any more than the old U did.
Anyway, using the MAC address like that was always a bad idea because it's so easy to spoof a device's MAC address on a network. Push tokens, you should know they're now scoped to the app, and I'll mention it was always a bad idea to cache a push token. You always need to use the value you get back from did register for remote notifications for device token.
And just one more thing on this list also to note is name pasteboards are now scoped to your team ID. So you can now share custom pasteboard content among your apps but no further. System pasteboard stays the same as it always has been. So the UDID is gone, but I know there's some developers tempted to find other ways to identify and track devices, what we call digital fingerprinting. But as far as we're concerned, it's also a no-no. You know, fingerprinting is sometimes used for things like targeted advertising or some kind of fraud detection and, you know, other purposes.
And it can be done even without collecting personal data. But, you know, the problem with it is lack of transparency. We really want users to be in control of what their apps do on their devices. So we've been beating the drum on identifiers for a while now. I'm going to move on, but I'd say that pretty much every app is now using the new identifiers. But if you've still got questions or concerns, you know, of course, we're more than happy to hear from you.
On the consent and transparency front, this is where, as I mentioned, we're giving the user more and more control. The OS intervenes between your app and the user when you want access to personal data or device features. And there are three things you need to do. You need to make sure that your app works well even when the user says don't allow.
You need to help the user by providing these what we call purpose strings make an informed decision about whether to grant your app access to their personal data. So here's a good example of an app saying exactly why it wants access to your location and what it will do with that information. And the third thing you need to do, very important, is test. Test every possible scenario to make sure your app works robustly as privacy settings can change.
Here's the list of everything that can trigger a consent alert. You know, when you ask for location to start updating the location or the image picker to access the asset library, etc. That's what triggers the consent alert. The user's consent or not happens outside the address space of your app.
You find out about it asynchronously, either through a delegate or a block method. A few things that we changed or introduced in iOS 7. So for social, that's the account store framework. We added a new one, a new account type for Tencent Weibo, which is the Chinese microblogging service.
For the camera now in some regions, if you ask AV Foundation for camera input, user will get a consent alert. So you need to be prepared to handle the user maybe saying don't allow. And also new in iOS 7, the microphone now. That'll trigger the consent alert. And if the user says no, your audio recording session is going to return silence.
Data stream will be all zeros. And last but by no means least, core motion. So if you're going to use core motion, that's also going to trigger a consent alert. And there are two things you need to do. You know, one, be prepared to handle the user saying don't allow.
In other words, Keep your app running with as much functionality, keeping it as useful and as engaging as possible, even when that happens. There's no telling the user what they should and shouldn't do. You've just got to make your app as useful as possible, even when the user says don't allow. Keep your app running with as much functionality, keeping it as useful and as engaging as possible, even when the user says don't allow.
Quick word about restrictions. Some of you may have apps where enterprise configuration�� sorry, apps running on devices where enterprise configuration profiles are installed or running your apps on devices where restrictions have been set manually. So whatever you do, don't tell the user to change their privacy settings because maybe the user can't. You've just got to keep your app running with as much functionality as possible.
I mentioned the purpose strings. This is where you help the user decide whether it makes sense to grant your app access. And very easy to do in Xcode, go into your app's Info.plist, look for things like the location usage description entry or the photo library usage description. Put in the reason why you want access, provide localizations, of course, help the user make an informed decision about granting your app access to some kind of personal data.
Testing, obviously important. Just make sure the right things happen. You know, when the user says okay, when the user says don't allow, when the user later changes her or his mind, and also when restrictions are in place. Now, the consent alert only comes up once per test run of your app, so maybe you're going to have to reset or toggle your privacy settings between one test run and the next.
And you have to do this kind of testing on the device. You can't use the simulator for this. And if you want to see how to handle consent alerts, fairly new sample code, Privacy Prompts, so I encourage you to download that and make sure your code leverages that sample code.
So that's data isolation and data collection. That's the last thing I want to talk about and I'm going to keep this fairly brief because we went into a lot of detail actually in the last two WWDC privacy sessions. You know, logging usage patterns and crashes and other events of interest obviously is helpful to you.
You know, you find out what features are most popular, where code needs to be tightened up, but you need to do it in ways to protect privacy of the user. And the way to think about it is the data you log, if that did fall into the wrong hands, could you explain to the user why you were collecting that data in the way you were collecting it?
Well, you need to do it in ways that protect the information you were collecting in a way that the user would understand and agree to. The bottom line is whether you're logging this kind of runtime activity on the device or collecting stats on your servers, you need to do it in ways that ideally eliminate any kind of sensitive information.
And somewhat related to this, I'm sure you all know, you should have a privacy policy statement explaining the data you collect, what you do with that data, and whether or not you share it with any third parties. And there's a link in iTunes Connect, as you can see here. Provide that link, and then that link's available to anybody running any App Store client on, you know, any of our products.
One last thing. I'm sure you all read the App Store review guidelines every week. There's an important section for privacy and I want to draw your attention. App Review added this last clause fairly recently, so pay attention to that if any of your apps are designed to be used by children.
So we've run through this checklist. Hopefully as I've been talking through these topics, you've said, "Yes, I do this, this, this, and this, all the right things." And if you do that, I'm happy. Congratulations and thank you. If you don't do all those things, then you've got some homework. But hopefully you're on the right track for all these security and privacy best practices.
Here's my contact info. Always happy to hear from you. And definitely the Apple Developer Forums is a great place to see what other developers are talking about with these topics. The CoreOS section is a great place to go and contribute and to, you know, to discuss various security and privacy topics. So thanks very much. And I'm going to finish here. We'll take a short break. And then last session of the day is going to be a great one. That's the hidden gems for iOS development. So thanks very much.