iOS Secure Coding Practices for Beginners 2018

Secure coding helps to protect user’s data from theft or misuse. Unlike, an insecure program can provide access for an attacker to take control of a server or even a user’s computer, resulting in anything from a denial of service to a single user to the compromise of secure data and secrets, loss of service, or damage to a multi-user server.

Nothing is So Secure

iOS applications and operating systems are constantly under attack. Like MITM, Hackers keep trying to look for security vulnerabilities. Every day, black hat hackers discover new vulnerabilities and publish exploit code for iOS. And attacker always keeps using those code to make a vulnerable system. You should take every security vulnerability seriously and work to correct known problems quickly.

Secure Coding can Make a More Secure World

As a developer you can make your code more secure by following such major attributes of an application:

Authentication – The Way the Users' Log-in

Use two-factor authentication as the first stage of safety. An intruder can face difficulties to gain access or to breach a person’s personal data when a person uses a username & password together with a piece of information. Two-Factor authentication does improve security because it no longer depends on the sole strength of the password.

Data at Rest – Stored Data on a Device

User’s personal data or sensitive data saved in a device must be encrypted. And the key which is used to encrypt the data must be secured within the code or retrieved from a server when the app starts.

Data Transfer – Received and Transmitted Data

Simply it just means the server and client app communication. In this case, Web Service helps to data transfer, which depends on HTTP protocol. For secure data transfer user HTTPS(SSL) within the communication. SSL Pinning is one of the most secure ways to data transfer.

Code Security – The App Code on the Client

The developer must not write some sensitive data as Strings within the code. The app executable file can be read as the text file and all strings used in the code will be shown there, though it’s very hard to read but why to take chance.
Objective-C, Swift written code doesn’t provide such information which can be used to perform reverse engineering on that.

Memory Integrity & Security – Debugging the Application

An app can easily be connected to a debugger and can be listened & modify the values in memory. It can even help to login to the app without user credential and can collect some personal data too.
So never keep such sensitive data in memory or delete it after it is used.

Application Tampering – Codes of the App Should not be Altered

There should be some integrity check which must be made for app p-list. Because application tempering is not possible at runtime, a hacker or an attacker may modify installation package, that’s why an integrity check has to be made for app p-list.

Let’s Talk About Some Core Level Coding

Now we know about attributes we can prevent from attacks, but as a good developer, you should also take care of your core level coding part such as functions parameters validation, URL handling, memory debugging, valid third-party frameworks. Following points checklist is suggested by Apple for iOS, Like:

Avoiding Buffer Overflows and Underflows

Buffer overflows are major security vulnerabilities as on the stack and heap. In program every time when a solicit input are in given like from a user, from a file, over a network etc, the inappropriate response may occur. For instance, the input data might be longer than what you have reserved a block for in memory.

Actually, Buffer Overflow is when an input data is bigger than its reserved block, and if it’s not getting truncated, other data in memory will be written by this input data. Similarly, when the input data is shorter than the reserved space (due to erroneous assumptions, incorrect length values, or copying raw data as a C string), this is called a Buffer underflow.

This is divided into two parts which are:

1. Stack Overflows:

Every application has a stack if the app is using multi-threading it has one stack in each thread. All locally scoped data are contained in a stack. Stack frames are units, which every stack is divided into. Every frame contains some data specific to a particular call to a particular function. Depending on compiler flags, it may also contain the address of the top of the next stack frame.

At the top of the stack on every function calling time, a new frame is added.And the top frame is removed every time a function returns. At any given point in execution, an application can only directly access the data in the topmost stack frame. (Pointers can get around this, but it is generally a bad idea to do so.) This design makes recursion possible because each nested call to a function gets its own copy of local variables and parameters.
Below is the Schematic view of the stack and how it works.

Basically, the app should check all input data to make sure it is appropriate for the purpose intended (for example, making sure that a filename is of legal length and contains no illegal characters). But most of the time programmer don’t check, thinking of that a user won’t do anything unreasonable.This becomes a serious problem when the application stores that data into a fixed-size buffer.

If the user is malicious (or opens a file that contains data created by someone who is malicious), he or she might provide data that is longer than the size of the buffer. Because the function reserves only a limited amount of space on the stack for this data, the data overwrite other data on the stack.
Below image is on the same Stack but after malicious buffer overflow.

In addition to attacks on the linkage information, an attacker can also alter program operation by modifying local data and function parameters on the stack. For example, instead of connecting to the desired host, the attacker could modify a data structure so that your application connects to a different (malicious) host.

2. Heap Overflows

Heap memory is used only for those instances and variable which are created at runtime. malloc invoked an equivalent function which relies on the allocation of a memory block or instantiates an object. Heap changes in a non-obvious way as a program runs, it is less obvious how an attacker can exploit a buffer overflow on the heap. To some extent, it is this nonobviousness that makes heap overflows an attractive target—programmers are less likely to worry about them and defend against them than they are for stack overflows.

Exploiting a buffer overflow on the heap might be a complex, arcane problem to solve, but crackers thrive on just such challenges.

For Example, A heap overflow in the code for decoding a bitmap image allowed remote attackers to execute arbitrary code.

A heap overflow vulnerability in a networking server allowed an attacker to execute arbitrary code by sending an HTTP POST request with a negative “Content-Length” header.

Reference: To know more about overflows detection

Validating Input and Interprocess Communication

Actually, there is a number of ways an attacker can take advantages of unvalidated inputs.
More like :

  1. Format string vulnerabilities
  2. URL commands
  3. Code insertion

Format String Attacks:

In the following code the syslog standard C library function is used to write a received HTTP request to the system log. Because the syslog function processes format strings, it will process any format strings included in the input packet:
/* receiving http packet */
int size = recv(fd, pktBuf, sizeof(pktBuf), 0);
if (size) {
syslog(LOG_INFO, "Received new HTTP request!");
syslog(LOG_INFO, pktBuf);}

Most of time format strings raise problems for the application. Just for example take a look at an input string inserted by an attacker

This string retrieves eight items from the stack. Assuming that the format string itself is stored on the stack, depending on the structure of the stack, this might effectively move the stack pointer back to the beginning of the format string. Then the %ntoken would cause the print function to take the number of bytes written so far and write that value to the memory address stored in the next parameter, which happens to be the format string.

So whenever the system has to access that memory location, this will usually cause a crash, but by using a string carefully crafted for a specific iOS, the attacker can write arbitrary data to any location. See the manual page for printf for a full description of format string syntax.
To prevent format string attacks, make sure that no input data is ever passed as part of a format string. To fix this, just include your own format string in each such function call.

For example, the call
may be subject to attack, but the call
printf(“%s”, buffer)

is not. In the second case, all characters in the buffer parameter—including percent signs (%)—are printed out rather than being interpreted as formatting tokens.

URLs and File Handling:

If you accept a command that causes your application to send credentials back to your web server, don’t make the function handler general enough so that an attacker can substitute the URL of their own web server. Here are some examples of the sorts of commands that you should not accept:

  1. myapp://cmd/run?program=/path/to/program/to/run
  2. myapp://cmd/set_preference?use_ssl=false
  3. myapp://cmd/[email protected]&file=some/data/file
  4. myapp://cmd/delete?data_to_delete=my_document_ive_been_working_on
  5. myapp://cmd/login_to?
  6. In general, don’t accept commands that include arbitrary URLs or complete pathnames.

Code Insertion:

Sometime attacker may be allowed to insert code into a program by non-validating URL command and text strings, which is executed in the program. You are at risk from injection attacks whenever your code works with data that is loosely structured and contains a blend of two or more different types of data.

For example, if your application passes queries to a SQL database, those queries contain two types of data: the command itself (telling the database what to do) and the data that the command uses. The data is typically separated from the command by quotation marks. However, if the data you are storing contains quotation marks, your software must properly quote those additional marks so that they are not interpreted as the end of the data. Otherwise, a malicious attacker could pass your software a string containing quote marks followed by a semicolon to end the command, followed by a second command to run, at which point the SQL database would dutifully execute the injected code provided by the attacker.

Reference: To know more about risks of unvalidated input

Race Conditions and Secure File operation

A race condition occurs when two or more threads can access shared data and they try to change it at the same time. Because the thread scheduling algorithm can swap between threads at any time, you don't know the order in which the threads will attempt to access the shared data

Here is a Classic Example Below

An application writes temporary files to accessible directories where you can set the file permissions of the temporary file to prevent another user from altering the file. However, if it exists, you could be overwriting data needed by another program, or you are accessing a file prepared by an attacker, in which case it might be a hard link or symbolic link, redirecting your output to a file needed by the system or to a file controlled by the attacker.

To prevent this, programs often check to make sure a temporary file with a specific name does not already exist in the target directory. If it exists, it should avoid a duplication of file name here. If the file does not exist, the application opens the file for writing, because the system routine that opens a file for writing automatically creates a new file if none exists.

Insecure file operations are a major source of security vulnerabilities. In some cases, opening or writing to a file in an insecure fashion can give attackers the opportunity to create a race condition. Often, however, insecure file operations give an attacker the ability to read confidential information, perform a denial of service attack, take control of an application, or even take control of the entire system.