Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2005-501
$eventId
ID of event: wwdc2005
$eventContentId
ID of session without event part: 501
$eventShortId
Shortened ID of event: wwdc05
$year
Year of session: 2005
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: ...

WWDC05 • Session 501

Security Tips for Software Developers

OS Foundations • 1:01:44

Make your applications more secure: Apple's engineers will guide you through the best techniques to use when writing applications. Learn about emerging security threats, how to handle data, avoid common coding pitfalls, and system services for security.

Speakers: Ron Dumont, Richard Murphy, Aaron Sigel, Simon Cooper

Unlisted on Apple Developer site

Transcript

This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.

Good morning. Okay, in this session, we will present ways to help you enhance the security of your software. We're explicitly not covering security from a system administration standpoint, since that's a whole separate topic and we want to focus on developers. There are companies who provide multi-day courses on application security.

So the best we can hope to do in this brief session is to give you a few signposts to help you along the way. Also presenting will be Richard Murphy, manager of the Data Security Group, as well as Aaron Sigel and Simon Cooper from Product Security. And we'll be available after the session for any further questions.

So we will cover security threats and trends, discuss the multi-user environment in which your application runs, give you some tips on data handling, cover common coding pitfalls, and mention a few system services to help enhance the security of your application. So let's begin. In this section, we'll talk about how systems can be compromised as well as attack trends. And the topics here can apply to any commercial operating system.

When we talk about a security attack, one of the first things we ask is, "What is being attacked?" The points of attack are going to be the main elements in the entire system, which is comprised of various software layers, as well as multiple users and their information. Most systems connect to the network, making it an element to consider when designing for security.

Let's look at the main classes of attacks. The first is an attack from a remote entity. We've seen this happen through enabling a service such as SSH and not using good passwords. Or through built-in vulnerabilities such as buffer overflows and network-based applications. The remote entity can then insert malicious code to control the system and access information. What does this mean to you?

If your application opens and listens on a port, or allows itself to be updated, or processes input from the network, or registers a URL handler to run functions without explicit user action, or reveals information in response to network queries, then your application could be a gateway for a remote attack. Another type of attack is a local attack. Here, a user on the system could take advantage of a weakness to gain elevated privileges. Alternatively, a user's information that they thought was private could actually be accessed by other users on the system, including the system administrator.

With a social engineering attack, a user on the system is influenced to install malicious software or divulge sensitive information that can lead to further attacks. The social engineering attack can be viewed as a bridge that turns a local vulnerability into one that can be exploited remotely, blurring the lines between local and remote vulnerabilities. Things to consider with the local or social engineering attacks include: Does your application even briefly run with elevated privileges? Does it allow code plug-ins or store potentially valuable user information? We've talked about several types of attacks. Now let's look at a few trends.

The first is that systems are becoming more networked at higher speeds and for longer periods of time wherever they go. This presents an increased window of opportunity for remote and social engineering attacks. It also elevates the scope of threats from a hacked system. Second trend: botnets. It's no longer the sole hacker going after a single system.

Automated tools are freely obtainable to exploit vulnerabilities in remote services or weak passwords. These botnets are self-replicating. Individuals with little or no programming skills can build a network of around 1,000 hacked systems within a week. We have reports of organized crime groups running networks of 50,000 to 80,000 bots.

Sophisticated rootkits are then used to secure a hacked system, protecting it from being taken over by competing botnets. These rootkits will gather sensitive information through various means and set up communication channels for propagation and further instructions. A group that tracks botnets has reported the following statistics over the last week. So this is just over the last week. Number of newly infected systems by unique IP address.

2,915,791 newly infected systems just over the past week. They're seeing around 981 active botnets and they're finding around 25 new botnets each day. The following is an example of a 100,000 system botnet that was recently discovered. And in case people can't read this, I'll read it for you. It's dated March 30th, and it says, "Chinese authorities said they've arrested a man accused of hacking into 100,000 computers. Coordinated attacks were manipulated by the hacker after he gained access to the PCs through the use of a virus. Up to 40,000 of the affected machines may be abroad."

So with botnets, the attack trends have evolved beyond pure OS-level attacks to denial-of-service attacks for fun and profit, with the highest activity and focus on information theft. A lot more could be said about this, and it's a thriving underground market. Banks and businesses are writing off huge sums of money due to fraud. Certain groups are also going after industry trade secrets, as well as classified government and military information.

Another trend is the growth of exploits. It only takes a single person to create an exploit. That's nothing new, but with Botnets, the exploit can now be plugged into various bot tools for rapid propagation within a matter of hours. We're seeing exploits for publicly disclosed issues appear faster and a decrease in the grace period after notification before an exploit is released.

Having said that, most problems come from exploits attacking old, unpatched systems. So I guess this might be a system administration talk after all. So to summarize, attacks can be in the form of remote, local, or social engineering. Social engineering attacks can turn a vulnerability that you thought was only local into a remote one. The window of opportunity for remote attacks is increasing with more pervasive and faster networking.

Botnets with tens of thousands of systems are out there. More and more, attacks are focusing in increasingly sophisticated ways to get valuable information. Attack tools are easily obtainable, and it only takes one person to create an exploit, which is then shared and quickly disseminated across a large range of attacking systems. So with those happy thoughts in mind, I'll now turn it over to Richard Murphy to talk about the multi-user environment.

Thank you. Hello. So I'm here to talk about Mac OS X being multi-user, but I'm really kind of curious. When we started off doing this session, we'd originally wanted to make it to help out application developers make their applications more secure. In particular, we had some requests to make of you that would help us out in our job to help make OS X one of the most secure OSs we have. Because if you look at the environment, the environment of Mac OS X is not only the OS and the apps that we provide, but the apps that all of you guys provide. How many saw Bertrand and Scott Forstall's meeting yesterday?

Okay, you notice how they went 11 down through one of all the things to make your applications great? Everybody? Okay, we're all programmers here. We know there has to be a zero. Number zero, please make it secure. So as we go through this, keep in mind all of these things as you're making your applications.

Okay, so Mac OS X has home directories. This is a key component in having a multi-user OS. Home directories are places for people to keep all of their stuff. In Mac OS 9, it used to be kind of ad hoc. People would make certain directories, and they'd put their documents there, and sometimes applications would adhere to where they put their documents using nav services, and sometimes they'd just bury it inside the applications folder.

Mac OS X, we actually partitioned or preformatted a home directory for users. The first thing we did is we made a documents directory. So if you have an application that deals with document formats, like Word, or possibly an accounting program or something like that, this is a place we expect you to put the user's data.

Library is actually used to keep the preferences, logs, caches, and anything else that needs to have a little bit more restricted access. Documents might want to be shared, but preferences usually you don't want to have shared. You don't want to have other people messing with it unless it's a managed environment.

Finally, we have the public directory. This is the place where we explicitly made it to put shared documents. You actually have the Dropbox in there. Finally, we have music and movies. We partition that out. iTunes keeps its music in the music directory. If you have other applications, it would be a good place to keep music. And same thing with movies.

Mac OS X has a couple home directory types. There's normal home directories. These are the ones that are created by default for every user. If you want to be a little bit more secure, or a lot more secure, you can make a FileVault home directory. FileVault home directories aren't ever mounted till the user actually logs in. They're encrypted on disk. They're actually a disk image, an encrypted disk image using AES-128.

If you store your files into a file vault, it adds a lot of protection. However, if an application keeps its temporary files in other places other than the home directory, you have to wonder a little bit how safe that actually is. So one of the things as an application developer is make sure that if you're dealing with users' document data, you keep temporary files somewhere within the user's home directory.

By default, FileVault is unreadable by any other users on the system. One of the other things to keep in mind is it isn't available if the user's logged out. So if you want to have a long-running process, you'll need to make special arrangements. Also, there's network home directories.

Network home directories are used a lot at various institutions. They have really different operating semantics. One of the things about a networked home directory is that it can be used by two different computers at the same time. If a user has two computers at their desk, or three or four, they can actually log into the same home directory at the same time. This obviously creates some data integrity issues if you don't program for that.

Make sure that you play well with the user's home directory. Don't change permissions on files. We've seen some applications at times whose installers will actually go out and just because it's a little bit easier, they make permissions 777. It's really easy to dump files into places that are 777. Unfortunately, it isn't real safe for the user's files. So, pay attention to the permissions the user set in their home directory. Work well with them. Don't change them spuriously.

And by the way, if you change them to 777 and then put them back, is that safe? It still leaves it open. There's always that little bit of time where it's open for a little bit while you're fiddling with the permissions that you've left the user exposed. So make sure you play well for the whole time.

Use the provided directories where you can. Don't just make things just because we're a little bit different. If you want to make something special for the user to keep their documents in, put it into the documents directory. So if you want to group all of your applications' files and data files, that's a good way to do it. But don't, in the home directory, make another directory to keep them in.

This will help out the user. It helps them organize their files. I know that we want to go with Spotlight to the nested folders don't really matter anymore, but if you're backing up, nested folders do a little bit. It really helps you find things that you want to back up. The user actually controls all of their data in their home directory. Make sure you keep this in mind. Don't help them out because you know better. Don't help them out because it makes your application easier. Make sure you adhere to their policies.

Fast User Switching. We introduced fast user switching in Panther. And we had some growing pains while we were doing that. All of a sudden we found a few applications that actually used shared memory regions that were global to the whole system when you used them. If you actually had two users on the system accessing the same application at once, they were having data integrity problems because the shared memory regions were colliding. The other thing is that a shared memory region used in this way could be used as a way to actually ship data between two users that the administrator might not want to have happen. Or it could be a way of eavesdropping.

So while you're developing your application, keep in mind fast user switching, the fact that you might be backgrounded, the fact that multiple users might want to use your application at the same time. Sometimes you might not want to allow that for licensing restrictions, and sometimes you might want to play off of that. These are all business decisions you need to make.

[Transcript missing]

Some applications actually are really system resources. Most backup applications, for instance, are actually a full system resource. They need to be able to see the whole system image while they do their work. In these cases, it's far better off not to actually have to have a user logged in in order for the application to actually work. When you're put into that kind of a case, you need to demonize and move yourself into the root bootstrap. You have to be very careful about when you actually put up dialogues.

We have a lot of cases right now of dialogues popping up over the login window and exploits of that where people actually gain root. We're trying to close all of these down. Some of this is our problem. Some of this is third-party problems. And so keep this in mind while you're working with your applications. And of course, we'll be working on our problems on that route as well. Startup items.

/library/startupitems permissions have actually been changed in Tiger. We won't blindly launch startup items that are actually writable by admin.

[Transcript missing]

You can either disable it, or you can fix the permissions on the spot. If you disable it, what happens right now is a .disabled file gets created in the startup item, which can be later on removed. It's a little bit clunky, but it actually works, and it helps us stop the security hole. In the future, we'd just like to not see this happen at all. So the other thing is admin and normal users.

When we started out on Cheetah, all users, we actually created an admin account and we created a separate normal account. And this really, it didn't fit well with the whole, we're kind of like Mac OS 9 and now we have Mac OS X and it runs about everything at least as good as Mac OS 9. And so we've kind of gone along making admin users the default.

A lot of people are seeing that this is actually a little bit of a problem, since we offer so many opportunities for admin users to rewrite things. So, a lot of users are doing what we did in the first place. They're creating an admin account, then they're creating a normal user account. Normal user accounts can simply escalate privilege to do things. You actually have to supply an admin login and an admin password in order to do so.

Normal users aren't in group admin, so they don't have access to some of the writable directories that we've left out there. Unfortunately, what we found is a lot of applications don't deal well with non-admin users. Either their installers don't do the right things as far as authorization goes, or the application, once it's installed by an admin user, the user's actually backed out, used their admin account to install it, and come back in as a normal user, The application just plain doesn't work.

Usually, this is a matter of the application hasn't used the right directories in the user's home directory. If there's other reasons that your application doesn't work, contact your developer relations person to help give you some advice on how to make things work a little bit better. We'd really like to see the normal user operation be very good in most cases.

One of the tools you can actually use to help yourself out in this is the authorization APIs. If you actually need to temporarily escalate privilege, you can actually make an authorization call to do it. The documentation for this is at the developer website. The other thing is that the authorization APIs actually tie into the authorization dialogues.

The authorization dialogues aren't put up by your application. They're actually put up as a client of the security daemon. The coolest thing about this is, if we add different ways to authenticate, like smart cards or biometrics or voice recognition, you'll get that all for free in your application. So, you can future-proof your application by using the Sec APIs whenever you have to do privilege escalation. Keychains.

So normal keychains are per user. Every user that has an account gets a keychain. And by default, the password for that keychain is synced with the login password. Hence, we call it the login keychain. In Panther and in Tiger, the actual name of that keychain is login.keychain. Previous to Panther, it was named after the user account. You can safely change the name of that login keychain to login.keychain and it essentially becomes a Panther/Tiger keychain.

But users may have more than one keychain. Matter of fact, a lot of users are beginning to find that they like to group their data. They like to keep secure notes in the secure note keychain. Or they might want to move off their certificates into a certificate keychain. Or they might have specific web passwords that they want to put into a separate keychain that has tighter controls on it.

So, when you're saving passwords for a user, if you pass a null to the setKeychainItemCreate call, it'll actually save it to what's called the default keychain. I'll go back into that a little bit more later. So, some users might be a little bit more security conscious, and they might use multiple keychains to group these. So, let's look at the special keychain types. There's the login keychain, which is automatically unlocked at login.

There's a thing called the default keychain. This is the place where the user wants to put new items. This is why you'd make that call to item create with null. Don't change that. Don't hardwire the login keychain. If the user set a default to a different place, they probably know where they want it.

An important system-wide keychain is X.509 Anchors. This includes all the root certificates for CAs. This is actually kept in /system/library/keychains and contains all the root certificates that we've vetted. Finally, there's a system keychain, which is used by system demons in order to keep passwords and other private things that they need, basically, even if there's no user logged into the system at all.

User Keychains. An important thing to remember about user keychains, this is almost like an admin note more than an application developer's note, is that you can't reset a password on a user's keychain if you don't know the original password. There was some documentation or some article out of, I think it was in Macworld, where somebody said, Change your login keychain password immediately because if the admin actually gets in and changes your password, they can get into your keychain. That's not true.

The admin doesn't have whatever you have set for your login and that keychain memorized somewhere else. They can't get into your login keychain. Now, if you didn't change your login password immediately, yes, the admin presumably could actually get at that. The other thing is that the security daemon acts as the arbiter of keychain access control. When a process actually wants to get at a keychain item, it actually makes a request to the security daemon. The security daemon evaluates an ACL that's set on a keychain item.

This has existed since at least Cheetah. and it determines whether or not that particular application is allowed to have access to the item. There's never a point where a whole keychain is read into the process address space of the calling process. It's all arbitrated through the security daemon. All private key operations themselves, for SMIME and SSL and all that kind of stuff, are actually performed within the security daemon, not within the user address space.

So user keychains are excellent places to keep passwords. We've made them pretty darn safe. They're triple-des protected. And they're cryptographically strong for the private portion of the item. If you'll notice, if you ever dump a keychain, you'll have the label portion, which might include the website, but the password, the private portion, is actually encrypted. And that brings us up to data handling with Aaron Sigel. Thanks. Hey, Er. Hey.

Hi, I'm Ron Dumont, and I'm here to talk to you about data handling. Basically, why should you care what I'm about to say? Your reputation is on the line not only as an application developer, but your company and also your product. So, what are we talking about? We're talking about two things here.

One of them is privacy, and the other one is protection. Both of them have slightly different goals. First, privacy is about keeping your data secret. Protection is more about stopping someone from modifying your data or someone from destroying it. So, we'll go into the two first, and then I'll show some examples of employing them.

Privacy. What we're talking about is what to keep private. Well, financial data, intellectual property, all those things, right? But in a greater sense, it's really anything you wouldn't want to have on a billboard on the side of the highway, right? I mean, you don't want everyone to see things. So where do people go wrong when they're trying to employ privacy in their applications?

Well, first of all, If you don't use the right file permissions, then it's sort of game over unless you're using encryption too. We'll talk about that. So basically, if you want to keep a file secret, you shouldn't have it world readable unless the contents are encrypted. Now, you shouldn't assume that the file is not going to be accessed by anyone because the system administrator can override any BSD file permissions. So if you're trying to protect something beyond the scope of the system administrator, then you should probably look into encryption.

Another place where people fall short is by logging too much information or providing error messages with secret information in them. So you have to make sure that if you're about to log something into, let's say, a world-readable location, you're not about to log some sort of secret credential in there.

Some people do employ some encryption, but there are two places where applications go wrong. The first one is by not using encryption, period. But if they do, sometimes they use the wrong encryption. They think if they come up with their own algorithm to obfuscate the data, that's fine. But it turns out that most of the time people get it wrong. It's very hard to write a secure crypto algorithm, and so basically you should stick to the things that are out there, which I'll talk about in a minute.

And finally, if you're going to handle sensitive information, like someone's banking information, you should make sure you actually employ some form of security. You'd be surprised at the number of applications where people just expect that they're getting something secure, and clear text sensitive information is being written in world-readable locations on their home directory.

So that's privacy. And protection has to do with the destruction and modification of your data. So you want to make sure you're protecting, obviously, important information, reports, anything along those lines. But you also have to make sure you're protecting your system configuration files and any resource that can modify your system configuration.

Because obviously, if somebody can modify your system to make it less secure, then your system can be compromised easier. And finally, you should make sure that you're protecting the content that your application is creating. You don't want to have a user, another user on a system, come along and blow away all of the content that someone's just created with your application. So once again, where people fall short with protection is, first of all, just in the implementation of the BSD file permissions.

Um... So the first thing is you need to make sure you have good file permissions, and you have to make sure that you're also protecting users from, make sure that a piece of data hasn't been modified. Then you want to make sure you sign it and that you've kept your keys secret and all that.

In addition, you want to make sure that obviously you do error checking and input validation, but Simon will talk more about those. So we've hit privacy and protection, and the question is sort of how does that relate to the real world? So here's a sample, you know, install of an application, and where privacy and protection come into play. So you can see protection has that icon, and privacy has the little confidential folder, so that'll come into play here.

So first we have the application itself. And you install it into its directory in /applications. And the important thing to notice here is we have a little protection icon on it because it's not writable by other users. It's only writable by root. So the reason why this is important is because you want to make sure that if something comes along and tries to replace the content of this application, like Trojan it or install some bundles inside it or anything like that, that it's going to have to be authorized first. So that's a level of protection you have against a piece of malware coming along or another user and just monkeying with what you have.

Murph mentioned startup items. This is the exact same reason why you'd want to secure your application. Your startup item is also executed. It's executed as root, usually. And if you don't have the right permissions on it, then it actually won't start now. You'll have to deal with the security fixer, which we can talk about later. And this is also anecdotally, this is where Opener attacked. So Murph mentioned that there were issues with people inserting Trojans into startup items directories. This is how it happened, because there were insecure permissions here.

Now, obviously, Murph mentioned that you can store cryptographically secure information, like you can secure private information using the keychain. That's where we think you should store all credentials. Not only because it's cryptographically secure and it won't be storing any passwords, clear text on disk, but it also has some other benefits, like, you know, if somebody's got it inside their home directory in their keychain, then they can take it with them wherever they go, and it's also only available when they're mounted if they're using FileVault.

And unfortunately, though, it's only appropriate for, you know, passwords or secure notes, small things. So for larger content, you can actually create encrypted disk images, which are just disk images that are encrypted, similar to how FileVault gets your home directory secure, and it provides you a level of privacy on, on your secure content.

So where does everything else live? This is inside the user's home directory. Inside, their preferences should be stored in the user domain. The log files should be stored in the user's log files. Temporary items and caches should all live in the user's cache, and the reason for this is because, first of all, library has more restrictive permissions by default, so you don't have to worry about other users coming in there and, you know, modifying those files, because this is a place where that user specifically should be storing content.

Also, remember that just because you've got content living inside the user's home directory, and it might be inside a directory that's got good permissions, you still want to make sure that you encrypt anything that would be bad for, let's say, the administrator to come along and read. You also want to make sure you're encrypting other content just in case the system gets compromised.

Privacy and protection: There might be some resources you'd like to have system-wide. They should live in /library. You shouldn't be writing to this as a regular user. This shouldn't have any user-specific content in it. Make sure you don't set it up so that users have to replace content in these directories or that anything in these directories is considered secure. By definition, they're system-wide and meant to be shared with multiple users.

That was just one case of privacy and protection in the file system case, but we actually have several different technologies available to you to provide privacy and protection on the network and also with other forms of local data. Obviously, there are different solutions, and the right one, you know, there are multiple choices for each thing, so you'd see what's appropriate for your application. But the important thing is that on the technologies, you can search for any of those on developer.apple.com and get a lot of information about how to use them. This is a quick sheet that shows you the breakdown of what they provide.

And these are all technologies that we think you should probably be implementing in your application because by doing that, you get a lot more security. And so implementation is a large section of an application that gets developed, sorry, specification. You want to specify what you're going to use. You want to specify using these in your application. But to actually talk about security holes and how they implement themselves when you actually go to code, here's Simon Cooper.

I listed up there. Thank you, Aaron. So here's what I'm going to talk about today. I'm going to talk a little bit about where security problems come from, some common coding design pitfalls. I'm going to cover buffer overflows and issue overflows, temporary file problems with race conditions, some feature combining things that can happen, and finally some installation considerations.

So, my colleagues have been talking about decisions you make when you're designing your program, the specification of your program. So, when you actually come and build a program, you have a build program, when you combine the specification and implementation, they're never exactly going to match. There's always going to be some gaps.

Now, on the left-hand side here, that's the area that your QA organization or you will work on to eliminate, you'll make that area smaller because it's what the program is not doing. You have a design for your program and it's not meeting the expectations. It doesn't quite make it. So what's this other area? This other area on the right.

This other area on the right is things your program does, extra things that your program does, that you may not be aware of. This is the area that the bad guys work in. This is the area where if you designed a program to handle some string and you pass it a really long string, it behaves differently.

So if you take all types of exploits and all types of problems, buffer overflows are the number one problem. And their experience and time shows that about 50% of all problems are buffer overflows. So they're a big area. They've been there for a long, long time. The first buffer overflow was in 1998. That's a really long time ago. And things aren't really getting any better. So the first thing to remember about a buffer is it always has size. And that size is always greater than or equal to zero. You can't have a negatively sized buffer.

So if you don't obey these rules, what things go wrong? Well, in a stack overflow, you can modify the execution path and you can take control of the program. You can change function arguments and you can modify local data so that the program, if it was going to go and do something and store one piece of information, will store something else.

Stack Overflows are usually trivial to exploit. That includes the PowerPC platform as well as the Intel architecture. Heap overflows. They can also be exploited in a very similar way. It's a little harder. You can modify program data and you can change the flow of a program. And I'll give you an example of how you can change the flow of a program. And they are very dangerous for C++ code.

And finally, and you have to remember this, the result of mallocing zero is not zero. I'll come back to that. So here's a typical Mac OS X PowerPC stack frame. And you can see that the stack frame goes down. And we have the caller, we have parameter area, and a linkage area. And then it saves, there's an area for saving registers, and then there's local variables. Now in this example, we're gonna place a buffer in the local variables area.

And when you overflow that, what actually happens The buffer overflow grows up in address, and overwrites saved registers, the linkage area, and the parameter area of the calling routine. So that's a stack problem. Now, the Intel architecture is very, very similar. You just shuffle these things around a little bit.

So here's a heap overflow. Now, the malloc routines on Mac OS X are a little different than traditional Unixes. The control areas actually have their data stored separately from the area that manages the allocation of space. This has some advantages in that if, for example, you're doing double freeze, the Mac platform is usually resistant to that kind of problem because you do not corrupt the heat pointers because the heat pointers are not stored the same way as they would on a traditional platform.

However, if you do have a buffer that gets overflowed, you can cause problems. So in the bottom area here on this diagram, there is a virtual C++ object. which will have function pointers in it, and if you do a heap overflow into the next object, then when you come and redirect through those virtual function pointers, you will change the flow of the program. So you can exploit C++ programs that are using virtual function pointers with a heap overflow.

So what can you do to avoid buffer and integer overflows? So I'm going to cover C mainly, and then I'm going to talk a little bit about C++ and Objective-C, and using some framework support to handle strings. And there's a little key here. The green stuff is things you should use. The red stuff is things you should avoid. So for safer buffer handling, we're going to talk about some C functions.

Everything you see here on the left is something you shouldn't use. Things on the right are things you should use. So there's the standard strcat, strcopy. Don't use those functions. You'll also notice that I've listed strncat and strncopy on the left-hand side. And I'll talk about why those functions are not so good in a minute. Also there's sprintf and vsprintf and the old favorite gets. Now going briefly back to sprintf, most people when they want to restrict the size of a string that they're printing will use something like %10s.

That's actually incorrect. What that really says there is the minimum width that I'm going to allocate for that string is 10. It's not the maximum width. So if you actually had a string which was 20 characters long, it would continue to write into that area. What you really mean in sprintf is percent 0.10s. To avoid that problem, if you accidentally make that mistake, you can use snprintf, as is indicated on the right-hand side. Now we're going to compare strcat functions with strncat and strlcopy. One last thing: always use unsigned variables for calculating sizes.

So here we have a very small program snippet. We're going to have a destination buffer, which has space for five characters. We have a source buffer. And to start out, we're going to put something tiny in it. So what happens when we use STR copy from the source to the destination?

What happens when we use STR in copy? And what happens when we use STR in copy? Well, in all three of these cases, what actually happens is Tiny gets copied into the buffer, and the gray area on the slide is the safe area, and the red area would indicate a buffer overflow.

So what happens when we change that and we now use a larger string? So in the case of strCopy, well, it's game over, right? You lost, because you overflowed the buffer. With strncopy, something slightly different happens. strncopy will copy the characters into the buffer, but it won't zero-terminate the buffer.

So you can still end up with a problem in your code because the string won't be zero-terminated. If you then go and try and use a pointer to that string, you will walk off into the red area, you may dereference unallocated memory, or you may copy extra things. For example, if you store the password after that, you may end up storing the password or sending the password out somewhere else. So that's pretty bad.

So what happens when you use strlcopy? Well, strlcopy does the perfect thing. It actually copies as much of the buffer as it can, and then it zero terminates. And it guarantees that it will zero terminate. One last thing with STRL copy, which is not true with STRN copy, is you cannot detect in the STRN copy case when you've got the situation where it did not zero terminate. So you always manually have to add a zero termination in the case where you're using STRN copy. STRL copy, you don't need to do that, and it actually returns the number of characters that it wrote up to. So it's much, much safer to use STRL copy.

So now we're going to talk a little bit about coding styles to avoid and coding styles to use. So on the left-hand side, there's a couple of coding styles that are not so good. For example, we have a buffer. It's 1,024 characters in size. And then some point later in the code, we actually make sure that we're less than 1023. We make sure there's room for the trading zero there. So we've done the right thing, but we've used a fixed constant.

And we've used a constant that, for example, if we went ahead and changed it and said, "Well, we don't actually need 1,024 characters because nobody ever passes 1,024 characters, and we need to reduce the memory footprint of our program, so we're going to change the allocation on the stack to 512." Now, the problem here is that there's somewhere else in the code that doesn't follow that change.

Also, so in the two cases, we're using a number which is related to, the number is related in the two cases, but there's nothing in the code that actually indicates that. So on the right-hand side are two ways to actually do this a little better. You can either use a hash define and then use that definition.

And in the second case, you can actually use the sizeof operator to automatically calculate, the compiler will calculate that for you. Now in the second case, there's a fledgling industry growing right now, which is looking at source code analysis. If you use things on the right-hand side, then those tools will have a much better chance of detecting and eliminating that what you've written is safe.

If you do things on the left-hand side, it will have a little harder time figuring out whether or not things are safe. And the big problem with these tools right now is that they're not very good. They're still under development. So they will bring up lots of false positives. So the more help you give them, the easier it is if you're using these tools.

So another kind of style that I see quite a lot is where you have a little function, it doesn't do very much, it just adds a suffix onto a buffer. Well, when you do this, and you do this in multiple places, you're almost guaranteed to get one case where you're going to overrun the size of the buffer, because you're not going to take into account that when you're copying the file name from some user-supplied data into the original file variable, that you're going to allocate and say, well, I need to make sure that there's enough room for the extension to be added on. So, the easy thing to remember here is that if you're going to use strlcopy, you're going to need to have a size. So, you need to pass that size when you're calling the extra function. So, on the right-hand side here, we pass the size through.

So now I'm going to talk a little bit about C++, Objective-C, and frameworks. So for C++ you can use the STL string handling functions to do the allocation of memory for you and the manipulation of memory. But there are some problems. And there are some problems with encoding type, whether you're using a char or a wchar, and if you need to convert between different encoding types when you're converting back to using, say, for example, a POSIX API, where you need a particular type of C string.

For Objective-C, you can use NSString. Again, you need to care when you're actually converting to C strings, because if you don't zero terminate correctly, you can end up with problems, and NSString will treat blobs, and you won't necessarily get a zero termination if you're not careful. So when you're parsing to POSIX APIs, there can also be some issues with converting that string into something that the POSIX API actually wants. But in this particular case, I've given an example, you can actually ask NSString to make sure that the encoding type actually matches what the file system wants.

Foundation has CFString. It's very similar to NSString, and you can interchange those strings together. It can be used in plain C code. It's a little bit messy. It's probably not the best string handling functions. But it is there if you want to use it, and you don't want to have to handle the management of buffers yourself.

So if you remember way back, right at the very bottom of one of the slides, I said the malloc of zero The problem with buffer overflow is that it is not zero. There's another class of problems which is very common and is related to buffer overflows, and that's an integer overflow. And that is, when you have a signed number, a very large signed number, and you add another signed number to that, it can actually go negative.

So if you're using signed arithmetic, and you're doing pointer manipulation, and you're adding things together, all of a sudden, if you start checking to see whether you've reached a limit, you can end up violating that limit just by adding positive things together. It seems kind of wacky, but that really does happen. Also, when you multiply numbers together, you can wrap around if you're using a 32-bit number. So, for certain sets of N and M here, you can actually get N and M to come out so that when you multiply them together, it comes out to be zero.

So the big problem is if N and M is under user control. So if you've got some kind of multimedia file that's got, let's say, an object of size M, and you've got N of these objects, and you carefully, in the format, at the beginning of the format, you say, well, there's an unsigned int for this and an unsigned int for that, then the user could actually supply values in that file that actually made it look like there was zero objects in that file. when in fact there was actually some real data.

So to avoid this, and this has happened by the way, this really has happened in real code, what you need to do is put some checks in to make sure that the user-supplied N and M, when you're doing the arithmetic, is not zero. In both cases, the N and M.

And also that when you come up with the result and you divide it by one of the factors, you find the other factor. If that comes out to be true, if that test comes out to be true, then you can go ahead and allocate the space. You're not going to end up with an integer overflow.

The other really, really easy way to avoid this problem is to put user-supplied limits on the M and M variables. So you say, well, N and M can't ever be bigger than 1024 each, right? And you know that if you multiply N and M together, the maximum that could be is 1 megabyte, and that's going to fit into a 32-bit number. So there's not a problem there.

So now we come to temporary files. Temporary files come up a lot. People use scratch files, and they always want to pick the name of that file they're going to use. If you actually write a file into a known location with a known name that's publicly writable, somebody else can get there before you and either put a symbolic link or put different content there that you may read or you may end up writing.

It's actually very, very hard to write a piece of code that actually checks and is safe when you're writing into a publicly writable space with a fixed name. I've got an example on the next slide which shows how difficult that is. So, with symbolic links, there's a problem of when you check, so for example, a way to avoid this would be to say, a naive way to avoid this would be to say, "I'm going to check to see whether the symbolic link exists." Right?

So, I'm going to say, I'm going to do a stat call, actually I'm going to do an Lstat call, and I'm going to see whether or not there's a symbolic link there. If there's a symbolic link there, well, I'm going to try and erase it, and then I'm going to create my file. And that way I'm going to be safe. Well, you won't be safe, because between those two operations, somebody else can come in and insert a symbolic link back there again.

This is particularly a problem when you're running as root and you're offering services on behalf of a particular user, because you will have permission to write to any file on the system. So you have to be very, very, very, very careful if you're running as root and you're using temporary files. Very careful.

So, as I said, it's very difficult for security creating fixed-name files in world-writable places. It's also dangerous to create directories in world-writable places with fixed names. Now, there's a very easy solution to this, and there's a set of functions called MakeSTemp, and there's a set of related functions, which will create a temporary file with a random name, which means that an attacker will not be able to guess that name in advance and place a symbolic link there and make you go off and do something bad.

Now this function takes a template string that you fill out, and this template string has a number of X characters in it, and those X characters get placed with random numbers. And there's an example here on the bottom of the slide where you're creating a temporary file. In this example here, it's actually giving you a file descriptor back to that file. It will already be open for you to use.

So as I said, I was going to give you an example of how to write a fixed-name file in a publicly-writable place. This is the code for doing that, and we will make this available to you after the conference. You can actually Google this and find it. This has been very well-known. And it appears in all the secure coding books. If you buy one of those secure coding books, you'll find a snippet of code like this in a secure coding book. So I'm not going to go over this. I don't have enough time to go over this.

So finally, we come to feature combining. So what is feature combining? Well, feature combining is where you take a really, really awesome feature and you combine it with a really wonderful feature. and you end up coming up with an awesomely wonderful security hole. And that's really horrible. Now, Apple has suffered from this. Last year, for example, we had cases of being able to automatically download disk images and then be able to use URI handlers and redirect through those URI handlers. And you had a combination of those two wonderful features and you ended up with a whole raft of exploits.

So what you need to be careful with is if you're using a framework that has a set of capabilities, you need to be aware of all those capabilities and the side effects that those capabilities might have. So for example, if you're using WebKit and you're loading a piece of HTML, you need to make sure that if you're not using JavaScript, you don't have that bit turned on in WebKit.

So finally, one of the big things that really gets security is complexity. The more code you have, the more bugs it's going to have. And you can view security bugs as like a small subset of just regular types of bugs. So the more bugs you have, the more security bugs you're going to have. So if you want to make less security bugs, you just make your code smaller, right? Very simple.

One of the other problems is that if you have to create code that's backward compatible, you need to have two sets of code. Well, in that situation, how many times are you actually checking the code paths when you make modifications? So testing becomes a big problem when you start to have legacy support. So advice is try and make your things as simple as possible. And if you can avoid generating situations where you require backwards compatibility, rather than saying, "I have a migration process forwards," then please do. Avoid having to support multiple versions of something.

So finally, you've created your program. There's no security bugs in it anymore because we've done all these things. And there are, of course, a whole raft of other security problems, and we unfortunately don't have time to go through all of them today. We would take up several days' worth of talking to talk about all the different types of security problems. But now you have, let's assume you've got a wonderful program now, and you want to package it up and deliver it to your customers. Well, security doesn't end with just writing your program. It actually, there are security considerations when you're actually delivering it to customers.

So, my colleagues talked a little bit earlier about using secure permissions when installing. So when you're dumping things down onto the disk, you shouldn't be saying, "Oh, it doesn't really matter what the permissions are. We're going to make it writable. We'll let the user clean that up." That's bad. People don't like that.

So, make sure you look at all of the permissions that you're laying down. If directories don't exist, make sure that those directories get created with sensible permissions and have sensible owners. Do not allow modification to your application bundle. We can't say that enough times. If you write inside your bundle, all sorts of nasty things are going to happen. Don't modify the permissions of system components.

That can really cause some interesting side effects if you, for example, need to write something into, let's say, I didn't think of an example, I'm sorry about that. So, library startup items. Supposing you say, I need to write something into library startup items, and I want everybody to be able to modify that because I'm going to store a preference file in there, and I want every user to be able to modify that. If you change the permissions on that directory, well, the system now has a defense, and it won't let you do that.

But if you do that in other areas, you can create security problems. Securely. And if you ever use a temporary file in an install script, you've got to use the makeSTemp functions. Otherwise, you're going to end up with the same kinds of security problems that occur when your application is running, because the installer quite frequently will be running with elevated privileges.

So now I'm going to wrap everything up. So we talked about attack trends. So they're getting increasingly sophisticated. They're automated. The bad guys are going after the user's data. There's money in that data, and they're going after it. Only one person needs to create an exploit. They share that exploit, then everybody can do it. So it may be hard, a problem may be very, very hard for two years, and then somebody figures out how to do it. Then everybody can do it, and every exploit that comes out after that uses the knowledge that somebody's gained.

Mac OS X is a multi-user environment. This means there's things going on in the background, there are other users using the system. It's not just you. Use the correct locations to store persistent and temporary data. Use the key chain to store passwords, secrets, and credentials. It's a very, very good mechanism. And if we get it wrong, well, you can blame us, right? If you write your own crypto and you get it wrong, well, it's gonna be your problem, not our problem.

Mac OS X system services can provide information, privacy, and protection, so FileVault and encrypted disk images. and File Permissions. And finally, secure coding. Buffer overflows are the number one floor. If you can reduce the number of buffer overflows that you have, then you're going to reduce the number of problems in your code by maybe up to 50%. They really, really do occur that often. So coding safely provides enhanced security, and it does improve your software quality. On that original slide where I had the specification and implementation, you can get those two things to come closer together if you take care and code securely.

And finally, installation is part of the security process. It's an end-to-end thing you have to take care of when installing your applications. So thank you very much, and for more information, you should... Oh, I haven't seen this slide. Okay. So for more information, the person to contact is Craig Keithley. He's the security technology evangelist, and his email address is up there. And I think we can probably put that slide back up again, but now we're going to switch to Q&A.