You want to learn how to improve your Android applications so that they're secure and robust. You would like to learn about mobile software security and its most important threats and vulnerabilities. You want your users to be satisfied while ensuring that their data is secure and that the application has no bugs. Can you do this easily? What do you need to do in order to achieve this?
This chapter will teach you the basics of software security. We'll begin by teaching you the different security terms that we will use in this book. You'll see the most important threats and vulnerabilities that may affect your application. You'll then learn about secure code design principles, as well as how to test our application for security issues.
In this chapter, we will cover the following topics:
Software security terms
Threats, vulnerabilities, and risks
Secure code design principles
In recent years, the Internet has experienced a huge increase in electronic commerce (e-commerce). This increase in monetization of information in the cloud means that attackers can now be rewarded financially, socially, and even politically for a successful attack. There is a low risk in attempting these attacks, since there is a small chance of getting captured and therefore, of prosecution. With a more motivated enemy, companies and enterprises have to improve their security measures to face these new threats. They must identify the threats and defend the vulnerabilities that may affect the data that has a big impact on their business.
In order to understand the content of this book completely, you will first need to understand some basic concepts about software security:
Asymmetric cryptography: This is also known as the public key cryptography and uses algorithms that employ a pair of keys—one public and one private. A public key is used to encrypt the data while a private key is used to decrypt data.
Encryption: This is a process through which a plain piece of data is transformed into an encrypted state, with the objective of concealing this information in order to prevent access from unwanted sources.
Man-in-the-middle attack: This is a type of attack where the attacker assumes a position in the middle of a communication, intercepts and reads the messages of a communication, and lets the victims believe that they are directly connected to each other.
There are three key terms that you need to understand. They were defined in the previous section, but we will talk a little bit more about them since they are commonly mixed up. These terms are threat, risk, and vulnerability and they are discussed in the following sections.
A threat is anything that may exploit vulnerability in order to access, modify, or destroy information. A threat is the source and type of an attack and is what we try to defend against. Threat assessments are used to determine the best way to defend against a determined class of threat.
When we consider a communication between two authorized entities, a source (S) and a destination (D), threats can be categorized into the following four segments:
Interception: This happens when an attacking entity has an access to a communication between two authorized entities. The entities do not realize that interception is happening and keep on with their communication normally.
Interruption: This refers to when the attacking entity intercepts the communication. The source entity may not realize this is happening, while the destination entity has no knowledge of the communication attempt.
Modification: This happens when the attacking entity changes the information sent between the two authorized entities. The destination entity does not realize that the information has been tampered with by the attacking entity.
Vulnerability is a weakness or a flaw in the security system of our application that may be used by a determined threat to access, modify, or destroy information. Vulnerability testing is mandatory and should be performed repeatedly to ensure the security of our application.
When a human or a system tries to exploit vulnerability, it is considered to be an attack. Some of the most common kinds of vulnerabilities that can be exploited to damage our system are as follows:
Improper authentication: This happens when an entity claims that it has been authenticated and the software does not check whether this is true or false. This vulnerability affects our system of access control, since an attacker can evade the authentication process. A very common example of exploiting this vulnerability is modifying a cookie which has a field that determines whether the user is logged in. Setting
truecan cheat the system into believing that the entity is already logged in and is therefore granted access when it should not be granted.
Buffer overflow: This happens when the software has access to a determined amount of memory but tries to read a buffer out of the limits. For example, if the software has a buffer of size N but tries to read the position N+2, it will read information that may be used by another process. This grants access and even modifies the information that belongs to a part of the memory where the software should not have access.
Input validation: When reading information provided by the user, it is always a good idea to validate the data. Not validating the data may result in an attacker introducing certain unexpected values that can cause an issue in the system.
SQL injection: This is a kind of input validation vulnerability. It is very common to use a search feature in almost any application. The string that the user introduces in the search field is then introduced in a SQL sentence. If there is no analysis and filter of the string provided by the user, an attacker could write a SQL query that would be executed. If this is combined with a bad access control, the attacker could even delete the whole database.
A risk is the potential for an attack happening and being successful. The more sensitive the information, the higher the risk of attack, as it can cause a higher level of damage to our system. Risks are the result of a threat exploiting vulnerability and accessing, modifying, or destroying a piece of information that we want to be protected. Risk assessments are performed to identify the most critical dangers and to evaluate the potential damage. This potential damage is calculated through a state between the cost of a breach happening, which depends on how sensitive the information is, and the probability of that event, which depends on the threats and vulnerabilities that may affect the application.
As you can see, there is a very important relationship between these three terms; especially when trying to correctly identify the risk that the information stored suffers. Assessing threats and detecting vulnerabilities is crucial to the protection of the information in our application.
In order to reduce the number of vulnerabilities of your application, a good security design is mandatory. There are many standards and guidelines that recommend different processes to produce secure applications. In this section, we are going to identify the most important principles that you should follow when designing your application:
Secure defaults: Security is of the utmost importance for an average user. When designing your application, you should make sure that the most demanding user is going to be satisfied and, therefore, your application should offer the best security methods available. However, there are some users who may prefer accessibility over security and may want to reduce the level of security. For example, you may want to add password aging to your authentication system. This means that every established period of time, the users should change their password to a new one. This means an additional level of security but can be annoying for certain users. Adding an option in the preferences to turn off this feature can be a good idea. However, always make sure to set the default to the more secure setting, and let the user decide whether they want to increase the risk of breaching their information.
Least privileges: Privileges are sometimes conceded in excess in order to speed up the process of development. This principle states that you should always concede the least privileges as possible in order to minimize security risks.
Clarity: Never trust obscurity to ensure the security of your application. Concealing the information on how your security system works is a good idea, but it should not be granted as enough by itself; the security must come from good cryptographic techniques and a good security design.
Small surface area: If you know you may have vulnerability in a determined section of your code, you can try to minimize the risk of a threat exploiting it by minimizing the overall use of this section. For example, if you think that certain functionality may be exploited, you can restrict this functionality to authenticated users.
Strong defense: When defending against a certain attack, there may be different methods to use. One control can surely be enough but sensitive information demands extraordinary measures. Also, using more than one method of precaution is most of the times convenient.
Failing securely: When developing our application, we aim for the highest robustness. However, applications fail sometimes and we need to adapt our code to make sure the application fails securely. When programming for Android, we can address this issue by controlling every exception, for example, through the correct usage of
Not trusting the third-party companies: There are many services available that have been developed by the third-party companies with different privacy and security policies. It is important to know that while using one of these services, you trust the companies on how they use your information. The principle of not trusting the third-party companies recommends that you should only trust an external service with the minimal amount of information possible and always implies a certain level of trust with them.
As stated by Boris Beizer, author of the book Software Testing Techniques, Dreamtech Press:
"Bugs lurk in corners and congregate at boundaries."
Security testing can be defined as a process through which we find vulnerabilities or flaws in our security system. Although we may do exhaustive security testing, it does not imply that no flaws exist. In this section, we will focus on the taxonomy of tests that can be performed in any circumstance.
Tests can be categorized into two big groups: white-box tests or structural tests and black-box tests or functional tests. Structural testing, more commonly known as the white-box testing, is a testing method that evaluates the internal behavior of a component. It is focused on the analysis of the behavior of each procedure in different moments of execution. The white-box test evaluates how the software produces a result. Functional testing, specification testing, or black-box testing, are methods of testing that focus on the functionality of the component rather than its structure. When using this kind of test, the tester is aware that a certain input should generate a particular output. This test evaluates what the software produces.
The two test categories, white-box test and black-box test, are shown in the following diagrams:
There are various white-box techniques. However, the most commonly used are control flow testing, data flow testing, basis path testing, and statement coverage and they are explained as follows:
The black-box testing design also includes different techniques. The most frequently used techniques are equivalence partitioning, boundary value analysis, cause-effect graphing, state transition testing, all pairs testing, and syntax testing, and they are explained as follows:
All pairs testing: This is a combinatorial method that tests every possible combination of parameters. When the number of parameters and the possible values for each parameter are big, this test technique can be combined with the equivalent partitioning technique to reduce the number of test cases.
Syntax testing: This analyses the specifications of a component to evaluate its behavior with a huge number of different inputs. This process is usually automatized due to the large number of inputs required.
When testing an application, there are different levels of testing that depend on the size of the part of the system involved. There are five commonly known levels of tests: unit, integration, validation, system, and acceptance.
Unit tests: These tests focus on each individual component. These tests are usually performed by the same development team and consist of a series of tests that evaluate the behavior of a single component checking for the correctness of the data and its integrity.
Validation tests: These tests are performed by the fully developed software in order to evaluate the fulfilment of functional and performance requirements. They can also be used to assess how easy it is to maintain or to see how the software manages errors.
The higher the level of testing, unit testing being the lowest and acceptance testing the highest, the more likely it is to use black-box tests. Unit tests evaluate components that are small and therefore easy to analyze in behavior. However, the higher the level, the bigger the system, and therefore the more difficult and more resource-consuming it is to apply white-box testing category. This does not mean that you should not apply the black-box testing category while performing unit tests, as each one complements the other.
In this chapter, learned the basic and most commonly used terminologies while discussing software security. You know the difference between threat, vulnerability, and risk, and understand how each one is related to the other. You also learned about the different kinds of threats and vulnerabilities that can affect a system. You now know how to properly approach coding your security system thanks to the secure code principles. Finally, you learned about the different methods of testing that you should consider in order to make your application robust. Properly understanding these definitions allows you to design better security systems for your software.
So as a developer, you have to address the security of your application, but what does Android do for you? Android has several built-in security measures that reduce the frequency and the potential damage that application security issues may cause. In the next chapter, you will learn about these features and understand how they work.