Empirical Evaluation of API Usability and Security
Today's computer systems often contain millions of lines of code and are constructed by integrating components, many of which are authored by various third parties. Application Programming Interfaces (APIs) are the glue that connects these software components. While the SEI and others have placed significant emphasis on developing secure coding practices, there has not been an equal emphasis placed on APIs. This blog post describes our recent research that aims to provide specific guidance to API designers to help them deal with the security issues regarding development of APIs.
Overview of API Security Vulnerabilities
APIs have had a long history of undermining the security of software systems. The C-string library was developed in the 1970s, and is still a major source of security issues. More recently, many webpages began to feature a button that allows users to log on using their Facebook credentials. Such webpages must use an API written by Facebook. Similarly, if the webpage uses another provider for authentication credentials, that provider's API has to be used. Unfortunately, researchers found that although these APIs were technically correct, they were very hard to use securely. Indeed, the research showed most web sites used them incorrectly, and users could have their Facebook or other credentials stolen (these problems were subsequently fixed).
This example illustrates that, ultimately, the cause of cybersecurity failures is flawed code written by programmers. After all, programmers are people too, and people make mistakes. It is not good enough for an API to be technically correct, it has to also be usable by other programmers, or failures will result.
Foundations of Our Work
Although it makes sense to design APIs to make them easy for programmers to use, there has been little work on how to do so, and common sense has proven unreliable. To our knowledge, we are the first researchers to study the security aspects of API usability.
Brad Myers, a professor at CMU's School of Computer Science, is a co-principal investigator on the project along with his doctoral student, Michael Coblenz. We are also collaborating with Jonathan Aldrich, another professor at CMU's School of Computer Science, and Joshua Sunshine, a systems scientist at CMU's Institute for Software Research, and Forrest Shull at SEI.
Our research concentrates on the usability and security of non-security-related APIs because we are interested in security issues that occur when programmers are focused on functionality, not security. Our research makes little distinction between APIs, software development kits, and language features. For example, concurrency is built into Java, but it is thought of as a library in C (although compiler-writers disagree with this). Also, C++'s
const and Java's
final have different semantics.
Ultimately, our research has three goals:
- Provide actionable and specific guidance to API designers about the impact of API design decisions on security and the interaction between usability and security.
- Provide guidance to language designers about language features that affect the ability of API designers to express important properties.
- Provide accepted methodology for research in this area.
The first stage of our research focused on interviewing and surveying professional programmers, as well as structured interviews with key API designers to identify security-related issues. The second phase of our work focused on designing and building prototype tools that allow designers to improve the usability and security of the APIs they build. The third phase of our work is conducting controlled experiments with students and programmers to validate and measure the results of our attempts to improve API usability and security.
Control of State and Mutability
One of the fundamental design decisions made by an API designer is how state is to be managed and controlled. For example, both the security and functional programming language communities highly recommend designing immutable objects, which are objects whose state cannot be changed after creation.
The following items exemplify this guidance:
- Oracle security guidelines stress that maximum reliance on immutable objects is a sound strategy for creating simple, reliable code.
- Java security guidelines stress that additional work is required for mutable objects to protect against vulnerabilities.
- Finally, mutability, which is closely related to TOCTOU attacks, involves changing the state of an object after permissions are checked but before sensitive operations are performed. Since immutable objects cannot have their state changed, using them prevents TOCTOU attacks.
Prior work done by one of Dr. Myers's former students, Jeffrey Stylos, raised interesting research questions. Stylos and Steven Clarke of Microsoft, in their paper Usability Implications of Requiring Parameters in Objects, studied the usability of two different ways of constructing objects in APIs. If you have an object "FooClass" that requires two parameters to be used successfully, there are two basic choices of how to construct the object, as shown in the following code:
Two fundamental patterns for object constructors:
foo = new FooClass(arg1, arg2);
foo = new FooClass();
Create-set-call implies objects must be mutable
In the first method, you simply require the programmer to supply both parameters when the object is constructed. The second method is to create a "blank" object and then have the programmer explicitly set the two parameters later. This second approach implies that the object must be mutable.
Surprisingly, Stylos and Clarke found that all the programmers they studied found the second method more usable. Programmers were more productive and generally liked APIs that created blank objects that must be filled in later. This method is disturbing to security experts, however, because there are many possible avenues for failures. This finding led to very concrete research questions: can we replicate this result and, if so, can we measure a trade-off between usability and security?
In the first part of our study, we conducted semi-structured interviews with experienced developers. We chose subjects who work on large projects, who all had a minimum professional experience of seven years, with a mean of fifteen years of experience. Our interviews focused on how they think about and manage state when writing software.
All our participants reported that control of state is a serious issue for them and one that plays an important part of system designs. For example, when asked about what percentage of bugs result from state changing when it should not have, one participant exclaimed:
"Most of them! ... My favorite is where you have data that is supposed to be immutable and is only settable once in theory but that's not well enforced, and so it ends up getting reset later either because it gets re-initialized or because someone is doing something clever and re-using objects or you have aliasing where two objects reference the same other object by pointer and you make changes ... ."
Another participant reported that one state-control issue ended up causing permanent friction between two groups. One module depended upon data that got changed by a third-party library, resulting in half-updated or not-updated state. Unfortunately, it was unclear which group was responsible for any given bug, which fostered mistrust between them.
Our subjects reported that a major issue with API design is that programming languages don't have adequate methods to specify how state should or shouldn't change. Java's
final and C/C++'s
const both superficially appear suitable for specifying restrictions on state modifications, but programmers complain that in practice neither of them are suitable. For example,
const is viral: to declare a method as
const programmers must also annotate all the methods that the first method calls, recursively, which can be a significant burden in large code bases.
In the next stage of our project, we designed language extensions to help API designers address the issues we found in our interview study. These tools enable designers to more clearly express restrictions on how state can be changed in the data structures defined by the API.
In total, we designed three language extensions to Java. Two of them allow the API to state that a data structure is immutable. Our interview study elicited two different, reasonable, definitions of what "immutable" might mean in an object-oriented language, and we have one extension for each definition. Currently, both of these extensions are implemented.
Our third language extension handles yet another use case: objects whose state is mutable during an initial set-up phase, but then afterwards becomes immutable. We are currently completing the design of this extension.
Naturally, after all the language extensions have been developed, we will have to validate their effectiveness, and thereby demonstrate that API usability and security can be improved. Although the SEI's participation in this project has now been completed, our partners will continue in this direction. In particular, they are planning a number of laboratory experiments in which programmers will perform tasks using both standard Java and our language extensions. These tasks will be chosen to reflect, to the extent possible, situations that occur in real development. In addition to measuring both the speed and errors (both security and non-security), they will also ask programmers to provide feedback on their thought processes as they perform the experimental tasks. This experiment will allow them to judge whether, in fact, our language extensions are correctly relating to how programmers think about their work.
Challenges and Future Work
Challenges with this research revolve around the fact that a lot of programmer decisions focus on maintaining the status quo. If programmers have coded a certain way for 40 years, and you ask them to code in a new way, sometimes they won't be as productive, not because the new method doesn't work, but simply because it is new. Conversely, in some cases programmers will try a new approach and are highly productive because it's new and shiny. Later on, when it is no longer shiny, the programmer realizes that the new approach wasn't as effective as the old method.
In future work, project team members plan to look at other issues related to balancing usability and security, specifically, error handling and injection attacks. Injection attacks occur when a developer writes a program in one language and constructs a program in a second language. These types of attacks are currently the most serious vulnerability in web applications today according to the Open Web Applications Security Project (OWASP). For instance, Java programs often do SQL queries to communicate with the database or create Java strip code that is run in a browser. We are interested in the findings that this next phase of our research will yield.
We welcome your feedback on our research in the comments section below.
For more information on API usability, please click here.
The paper Exploring Language Support for Immutability that I coauthored with Michael Coblenz, Joshua Sunshine, Jonathan Aldrich, Brad Myers and Forrest Shull was published at the 38th International Conference on Software Engineering. To read it, please click here.
To view the paper on which this project is based Comparing Transitive to Intransitive Object Immutability by Michael Coblenz, Joshua Sunshine, Brad Myers, Sam Weber, and Forest Schull, please click here.
To view the paper Empirical Evaluation of API Usability and Security by Sam Weber, Robert Seacord, Forrest Shull, David Keaton, Brad Myers, Michael Coblenz, which was presented at the Layered Assurance Workshop 2014, please click here.
To read the paper, Usability Implications of Requiring Parameters in Objects' Constructors, please click here.