Thursday, January 31, 2019

Architectural Security Weaknesses in Industrial Control Systems (ICS)

By Mehdi Mirakhorli (@MehdiMirakhorli) Associate Editor and Danielle Gonzalez (@dngonza) 
Center for Cybersecurity at RIT

Industrial control systems (ICS) are computers that control any automation system used in industrial environments that include critical infrastructures. They allow operators to monitor and control industrial processes and support the day to day operations of manufacturing, oil and gas production, chemical processing, electrical power grids, transportation, pharmaceutical, and many other critical infrastructures. Ever since the Stuxnet attack on modern supervisory control and data acquisition (SCADA) and PLC systems, there have been many vulnerabilities discovered and reported for these systems. Recent studies have shown that the documented cases of attacks to ICS infrastructures have exponentially increased from a few incidents to hundreds per year. In this blog post, we discuss common security architectural weaknesses in ICS.


We conducted a study that took several months in which we collected and analyzed 988 security advisories that disclosed ICS vulnerabilities. These vulnerabilities were received from the Industrial Control Systems Cyber Emergency Response Team (ICSCERT). We performed a detailed analysis of the vulnerability reports to measure which components of ICS have been affected the most by known vulnerabilities, which security tactics were affected most often in ICS and what are the common architectural security weaknesses in these systems 
Figure 1 shows a typical architecture of ICS. Programmable Logic Controllers (PLCs) and Remote Terminal Units (RTUs) connect to sensors and actuators through a Fieldbus to gather real-time information and provide operational control of the equipment. These controllers also communicate to a data acquisition server (SCADA) using various industrial communications protocols.


ICS relies on Human-Machine Interfaces (HMI) to configure the industrial plant, troubleshoot the operation and equipment, run, stop, install and update programs, and recover from failures. The day to day operational data is logged by the Data Historian component for further analysis and diagnosis. Each of these components has its own interfaces and can be the target of attacks that impact industrial equipment and operations. 


Figure 1. Overivew of an ICS Architecture


Our analysis detected 17 ICS components in 544 ICS advisory reports (55.06% of the entire corpus). Figure 2 is a heat map showing the most common vulnerable components in these ICS advisory reports. The size of each block in the heatmap represents the frequency of a component. 


Human-Machine Interfaces (HMIs), Supervisory Control And Data Acquisition (SCADA) Software, and Programmable Logic Controllers (PLCs) are the most vulnerable ICS components.
The remaining components were significantly less vulnerable. For instance, the fourth component impacted by vulnerabilities is OPC (reported 57 times) which is a software protocol based on Microsoft’s Distributed Component Object Model (DCOM), used by manufacturers for interoperability of industrial processes in real time.

We examined how many of the vulnerabilities had an architectural root cause by identifying the Common Architectural Weakness Enumeration (CAWE) assigned to each vulnerability and noting how many were associated with architectural tactics:
62.86% of ICS vulnerability disclosures had an architectural root cause, while 37.14% of the vulnerabilities were due to coding defects.

The most common architectural root causes for ICS vulnerabilities:

Improper Input Validation affects ICS the most, followed by Cross-site Scripting, Cross-Site Request Forgery, SQL Injection,  Improper Authentication

Table III shows the top 20 architectural CAWEs affecting ICS.

Table 2. Top CAWEs in Industrial Control Systems

1) Improper Input Validation: This weakness occurs when an ICS component either does not or incorrectly implements Validate Inputs tactic. Our analysis indicates that this weakness can be present in every ICS component and the consequences often results in a denial of service attack. For instance, ICSA-14-079-01 reports two vulnerabilities impacting Siemens SIMATIC S7-1200 Programmable Logic Controllers (PLCs). The crafted packets sent on 2 specific ports could initiate a special “defect mode” on the PLC device. The subsystem receiving the packets fails to validate, thus causing a vulnerability that can be exploited remotely and causes denial-of-service. These vulnerabilities were viable since the devices were accessible through the internet, however, they were mitigated by Siemens new versions of these PLCs. 

2) Improper Neutralization of Input During Web Page Generation (’Cross-site Scripting’): This weakness occurs in an ICS component that has a web-accessible UI, but does not or incorrectly “neutralize” input provided by one user (commonly a web request) than is subsequently used to generate web pages which are served to additional users. With this flaw, attackers can inject client-side scripts into web pages viewed by other users. This weakness is related to the Validate Inputs tactic, however, it is limited to ICS components with web-accessible UIs. In contrast, the previous weakness (CWE-20) presented the cases that attackers could implement a denial of service attack using a crafted input, that did not necessarily involved web applications. ICSA-15- 342-01 describes a cross-site scripting vulnerability affecting XZERES 442SR Wind Turbines. The web-based operating system of the turbine generator did not properly neutralize incoming web request content. This vulnerability could be exploited remotely and could cause a loss of power for the entire system. 

3) Improper Authentication: A common design weakness discovered in ICS is that a component fails to or incorrectly verifies the identity claims of an actor interacting with it. For instance, ICSA-17-264-04 reports that iniNet Solutions GmbH’s SCADA Web server assumed the SCADA is used in a protected network and did not implement “Authenticate Actor” tactic at all. However, the system was connected to the Internet. In another case, ICSA-16-308-01 describes vulnerabilities in multiple versions and models of Moxa’s OnCell Security software, which are cellular IP gateways that connect devices to cell networks. Access to a specific URL is not restricted, and any user may download log files when the URL is accessed. This can be exploited and used for an authentication bypass, where the malicious actor accesses the URL without prior authentication. 

4) Improper Access Control: This is a weakness in Authorize Actors tactic that occurs when an ICS component fails to or incorrectly restricts an unauthorized actor from accessing resources or equipment. This weakness can result in privilege escalation, the disclosure of confidential or sensitive data, or execution of malicious code. ICSA-13-100-01 discusses a case that MiCOM S1 Studio Software which is used to configure parameters of electronic protective relays fails to limit access to executables, meaning users without administrative privileges can replace the executables with malicious code or perform unauthorized modification of the relay parameters. The malicious actor could also exploit this to allow other users to escalate their own privileges. Exploiting this vulnerability requires physical access to the device and it can’t be exploited remotely. The company provides mitigation strategies for users, but it has not been patched or fixed by adding appropriate security tactics. 

5) Cross-Site Request Forgery (CSRF): ICS components may not verify that an expected and/or valid request to a web server was sent intentionally by the client (a.k.a. “forged” request). A malicious entity could take advantage of this weakness to force or trick a client into sending an unintentional request to an ICS component or equipment, which appears to be valid to the SCADA server or process controllers. ICSA-15-239-02 describes a cross-site request forgery (CSRF) vulnerability in the integrated web server of Siemens SIMATIC S7-1200 CPUs, which are used in Programmable Logic Controllers (PLCs). A user with an active session on these web servers could be tricked into sending a malicious request, which would be accepted by the CPU server without verifying intent. This can be exploited remotely, and would allow the malicious entity to perform actions to the PLC using the tricked user’s permissions. 

6) Use of Hard-coded Credentials: occurred when ICS components stored any type of credential used for authentication, external communication, or encryption of data in readable formats (e.g. plain text) in discoverable locations. This weakness compromises an Authenticate Actors tactic in ICS, and enables malicious actors to implement authentication bypass exploits and make ICS components or equipment perform actions that require authentication or elevated privilege. This weakness was prevalent across all ICS components. For instance, ICSA-15-309-01 discloses a hard-coded SSH key in Advantech’s EKI-122X Modbus gateways, which integrate Modbus/RTU and Modbus/ASCII devices to TCP/IP networked devices. The firmware of these gateways contains unmodifiable, hard-coded SSH keys. Since these keys cannot be changed but are discoverable, they could be remotely exploited to intercept communication by a malicious external actor. 

7) Improper Neutralization of Special Elements used in an SQL Command (’SQL Injection’): This is another weakness in ICS that affects implementations of the Validate Inputs tactic. It describes an ICS component’s incorrect or failure to “neutralize” user-provided inputs which are inserted as parameters to SQL queries, which can be exploited in SQL Injection attacks. In such cases the un-handled input is executed as part of the query itself instead of as a parameter. This can lead to the database unintentionally returning sensitive data or modification of the existing data. This weakness was mostly associated with components such as Human-machine Interface (HMI), Supervisory control software (SCADA) and variants of SCADA (e.g. Process Control System (PCS)). ICSA-14-135- 01 discusses a SQL injection vulnerability in several versions of the web-based CSWorks framework that is used to build process control software. The framework fails to sanitize or validate (“neutralize”) user provided inputs which are intended to be used to read and write paths. 

8) Use of Hard-coded Password: Hard-coded passwords are passwords stored in plain text or easily decryptable formats that are located somewhere discoverable by malicious actors, who can exploit them to bypass authentication or authorization checks. This weakness affects implementations of the Authenticate Actors tactic in ICS products. For instance, ICSA-12-243-01 report describes a privilege escalation vulnerability in multiple versions of two varieties of GarrettCom Magnum MNS-6K Management Software, which is used for device management on managed Ethernet switches. An undocumented but discoverable hard-coded password could allow a malicious actor with access to a preexisting account on a device to elevate their account privileges to admin levels. With these elevated privileges, a denial-of-service attack could be rendered or sensitive equipment settings could be changed. 

9) Insufficiently Protected Credentials: This weakness occurred when the ICS components used an insecure method for transmission (e.g. insecure network) or storage (e.g. plain-text) of credentials. This insecurity can be exploited for malicious interception or discovery. This weakness affects implementations of the Encrypt Data tactic. ICSA-16-336-05B discusses unprotected credentials which can be exploited in multiple versions of 3GE Proficy Human Machine Interface (HMI), Supervisory Control and Data Aquisition (SCADA), and Data Historian products. In these products, if a malicious actor has access to an authenticated session, they may be able to retrieve user passwords not belonging to the authenticated account they are using. However, it cannot be exploited remotely. 

10) Improper Control of Generation of Code (’Code Injection’): This weakness occurs when the ICS components fail to or incorrectly “neutralize” user-provided input to remove code syntax. This can result in this code being executed when the input is used to generate a code segment in the software. This weakness affects the Validate Inputs tactic. ICSA-14-198-01 discusses a code injection vulnerability affecting some versions of Cogent Real-Time Systems, Inc’s DataHub, a middleware used to interface with various control systems. If a malicious actor has access to and creates a ‘Gamma’ script on the local file system, he/she can craft a specially formatted user name and password to perform a code injection attack via an ASP page to execute that script file.

Finally, we looked at which tactics are most often compromised in ICS.


The top 3 most compromised architectural tactics in ICS are Validate Inputs, Authenticate Actors, and Authorize Actors.

Furthermore, our finding indicates that:



OWASP Top 10 covers the critical Web Application Security Risks, however, it does not adequately present the risks in ICS.  Here you can learn about Top 20 security risks in ICS.

Summary:

  • Many modern HMIs are now web-based and there are cloud-based SCADA systems, therefore common web vulnerabilities affect these components of ICS.
  • The most common architectural weaknesses in ICS is different than for web applications (OWASP top 10).
  • ICS are most vulnerable to CWE-20 Improper Input Validation that can result in denial of service attack, crashing ICS process and equipment.
  • ICS components are not secured by design. Many vendors have indicated that their products are designed to be used in a protected environment and therefore do not have mitigation techniques (e.g. authentication and input validation tactics) required to work in an untrusted environment.
  • Industrial control systems rely on many vendors for PLC, RTU, IED and other controllers and equipment. This increases their attack surface and makes enforcing Input Validation tactic difficult.

In a paper to appear at ICSA 2019[1], we report these findings in greater details and present advice for practitioners, such as Isolate control system devices and/or systems from untrusted networks.



You may also like:

Joanna C. S. Santos, Anthony Peruma, Mehdi Mirakhorli, Matthias Galster, Jairo Veloz Vidal, Adriana Sejfia: Understanding Software Vulnerabilities Related to Architectural Security Tactics: An Empirical Investigation of Chromium, PHP and Thunderbird. ICSA 2017

Joanna C. S. Santos, Katy Tarrit, Mehdi Mirakhorli: A Catalog of Security Architecture Weaknesses. ICSA Workshops 2017: 220-223

M. Krotofil and D. Gollmann, Industrial control systems security: What is happening?, 2013 11th IEEE International Conference on Industrial Informatics (INDIN), Bochum, 2013.


S. McLaughlin et al., The Cybersecurity Landscape in Industrial Control Systems, in Proceedings of the IEEE, vol. 104, no. 5, pp. 1039-1057, May 2016.







[1] Danielle Gonzalez, Fawaz Alhenaki and Mehdi Mirakhorli, “Architectural Security Weaknesses in Industrial Control Systems (ICS): An Empirical Study based on Disclosed Software Vulnerabilities”, International Conference on Software Architecture, Hamburg, Germany, March 2019.

Wednesday, January 30, 2019

Launching 2019


Launching 2019!

By: Xabier Larrucea 

During these last months, we have been revamping the approach for this blog. In fact, this blog is aligned to the mission of the IEEE Software magazine: ”IEEE Software‘s mission is to be the best source of reliable, useful, peer-reviewed information for leading software practitioners”)[1] . In this sense, the IEEE Software blog is the forum for publishing technical and free results aligned to the IEEE Software magazine mission.

Basically, the success of this blog is based on the contributions made by top researchers in the field, and by an accurate list of experienced associate editors which contribute directly to publish high quality posts. In fact, each associate editor receives, reviews and manages contributions, and provide support for each post.

Fig. 1 How do we work

It is worthy to note that these articles in the form of posts are not referenced as it is traditionally understood. However, researchers can share their works, and to contact other researchers/practitioners aiming to contribute to these topics. Therefore, this blog can be used as a way to share the latest results and to contact other researchers/practitioners aiming to contribute to these posts. In fact, our main goal is to link research to practice and practice to research, and it complements other efforts including magazine and SE Radio and feature in progress ideas/research results. In addition, these posts create an ecosystem of articles around different topics, and they can be seen as seeds for creating new articles or enhanced articles which may be submitted as regular articles or as articles for special issues.  

This blog is part of the multimedia tools used for promoting the IEEE Software magazine, including not only special issues’ articles but also SE Radio podcasts and the different social networks. The success of these tools, and basically the success of this blog, relies on the active and constructive contributions from the Software Engineering community.

Finally, I would like to take this opportunity to thank Mei Nagappan (@MeiNagappan) as Editor of this blog and for his great efforts on creating and supporting this blog along these last years. In addition, I would like to extend these congratulations to the existing associate editors which are contributing extensively with the success of this blog. In fact, this list has been reinforced and extended with new associate editors. From now on, I will take over the responsibilities of Mei as Editor of this blog.

So stay tuned because more improvements  and new opportunities are coming soon, and please contact any Associate Editor or even myself (Xabier Larrucea) for publishing your technical articles!





[1] https://publications.computer.org/software-magazine/about/

Monday, November 12, 2018

Correctness Attraction: A Study of Stability of Software Behavior Under Runtime Perturbation

By: Benjamin Danglot, Philippe Preux, Benoit Baudry, Martin Monperrus (@diversifyprojec, @stamp_project, @martinmonperrus)
Associate Editor: Federica Sarro (@f_sarro)

In the introductory class of statics, a branch of mechanics, one learns that there are two kinds of equilibrium: stable and unstable. Consider Figure 1, where a ball lies respectively in a basin (left) and on the top of a hill (right). The first ball is in a stable equilibrium, one can push it left or right, it will come back to the same equilibrium point. On the contrary, the second one is in an unstable equilibrium, a perturbation as small as an air blow directly results in the ball falling away.

Figure 1: The concept of stable and unstable equilibrium in physics motivate us to introduce the concept of “correctness attraction”.


In one of his famous lectures [2], Dijkstra has stated a fundamental hypothesis about the nature of software, “the smallest possible perturbations – i.e. changes of a single bit – can have the most drastic consequences.”. Viewed under the perspective of statics, it means that Dijkstra considers software as a system that can only be in an unstable equilibrium, or to put it more precisely, that the correctness of a program output is unstable with respect to perturbations.

In our recent work [1], we have performed an original experiment to per- turb program executions. Our protocol consists in perturbing the execution of programs according to a perturbation model and observing whether this has an impact on the correctness of the output. We observe two different outcomes: the perturbation breaks the computation and results in an incor- rect output (unstable under perturbation), or the correctness of the output is stable despite the perturbation.

Let’s consider the PONE perturbation model which consists in increment (+1) integer values at runtime. At some point during the execution, we increment an integer value. An equivalently small perturbation model is MONE, which decrements integers. In Dijkstra’s view, PONE and MONE are the smallest possible perturbations one can do on integer data.

We perform the experiment on 10 Java programs which size range from 42 to 568 lines of code. They all have the property that we can perfectly assess the correctness of the output thanks to a “perfect oracle”. These programs and their oracles are described in Table 1. 

Table 1: Dataset of 10 subject programs used in our experiments.

In total, we perturb 2917701 separate executions of the ten programs. Among those 2917701 perturbed executions, 1977199 (67.76%) yield a correct output. This result surprised us, because it goes against the com- mon intuition that programs are brittle. Our literature review revealed that this empirical phenomenon has no name, yet. 

Correctness attraction

When a perturbation does not break output correctness, we observe “stable correctness”. This is conceptually related to the concepts of “stable equilibrium” and “attraction basin” in physics. Due to this conceptual proximity, we name the observed phenomenon: “correctness attraction“. As shown in Figure 1, the intuition behind correctness attraction can be graphical. The correctness attraction basin at the left hand-side of Figure 1 refers to the input points for which a software system eventually reaches the same fixed and correct point according to a perturbation model.
If you want to read more about this fascinating phenomenon, we discuss the reasons behind correctness attraction in our paper [1].
This original work opens interesting directions in the area of software reliability. If we engineer techniques to automatically improve correctness attraction, we would obtain zones in the code that can accommodate more perturbations of the runtime state, and those zones could be then deemed “bug absorbing zones”.

References

[1] B. Danglot, P. Preux, B. Baudry, and M. Monperrus. Correctness Attrac- tion: A Study of Stability of Software Behavior Under Runtime Perturba- tion. Empirical Software Engineering, 2017.
[2] E. W. Dijkstra. On the cruelty of really teaching computing science. Dec. 1988.

Wednesday, October 31, 2018

Lessons Learned from Bad API Design

By Sven Amann (@svamann), Sarah Nadi (@sarahnadi), and Titus Winters (@TitusWinters)
Associate Editor: Sridhar Chimalakonda (@ChimalakondaSri)

Software libraries and their Application Programming Interfaces (APIs) are essential for proper code reuse that leads to faster software development and less software bugs. However, a poorly designed API can end up causing more harm than good: clients of the API may incorrectly use certain functionality leading to runtime failures, performance degradations, or security issues.
Over the last couple of decades, several program analysis techniques have been proposed to catch bugs arising from incorrect API usage [1]. Some of these techniques rely on mining patterns of API usages, whether from code or logs, and finding violations of these patterns, while others rely on checking that client code respects explicit annotations in the API code. Some languages come with annotations that allow the API designer to indicate certain restrictions on expected values or behavior (e.g., @Notnull or @Nullable in Java). Such annotations allow static checks of client code to warn the developer, e.g., when a null reference is potentially passed in a place expecting a non-null reference (e.g., IntelliJ has support for this https://www.jetbrains.com/help/idea/nullable-and-notnull-annotations.html). However, unfortunately, such annotations are still not consistently used by API designers. Additionally, the space of possible violations and things that can go wrong is unbounded. Thus, there may be desired checks or API design problems that have no corresponding annotations. That is: even meta-design via introducing annotations cannot solve all design problems. At some level, some design problems can only be identified through experience.

Moreover, the above checks and similar analyses are all posteriori measures that typically catch only a subset of the problems. In this blog post, we take the stand that we should try building APIs that are hard to misuse in the first place. We provide a set of lessons learned from common examples of problematic API design decisions. These lessons are based on our own experiences, whether as part of industrial work or part of our research, as well as examples from various sources. This list is by no means comprehensive, but a start for collecting common pitfalls of API design. The idea for this blog post was born out of our discussions during the 2nd International Workshop on API Usage and Evolution (WAPI ‘18) in May 2018 in Sweden.

Lessons from Bad API Design

Lesson 1: Avoid the Name/Action Mismatch

Description: Most design guides (rightly) point out that types should be named as nouns (string), mutating/non-const methods on those types should be named like verbs/actions (reset), and const accessors should be named like adjectives (is_blue()) or actions (find, count)). Sometimes, we don’t get that right.

C++ Example: In the C++ standard library, all containers (vector, set, list, etc) have an .empty() method on them. In English, empty is both an adjective ("The glass is empty") and a verb ("Please empty the trash.") As such, it is entirely possible to encounter code that invokes empty() and does nothing with it.
std::vector<int> v = GetInts();
v.empty();  // Does nothing!
v.clear();  // Does what the author of the previous line probably meant
Java Example: In the Java Class Library (JCL), BigDecimal.setScale(...) does not actually set the scale on the receiver, but instead returns a new object with a different scale.
Another example is the peek method on Java’s stream API. The name suggests that by calling this method, the code peeks at the first element in the stream. However, calling the method actually just returns a copy of the stream and nothing happens. The peeking only actually occurs when the stream is processed, e.g., by calling collect() or forEach().

Solution: Be very sure about your choices in naming. Make sure to consider all interpretations of your chosen API names. Be extra cautious about possible interpretations from non-native speakers. In the event that your chosen names can be misinterpreted, but changing the name isn’t an option, it may be useful to try to mitigate the problem. In C++, this has been done by adding the [[nodiscard]] attribute to the function. With this attribute, a compilation warning will be issued if the return value of the function is not used in some fashion. It’s likely that any pure function (sqrt(double)) and any side-effect free const method (empty()) should be tagged [[nodiscard]] to help identify bugs in client code.

Lesson 2: Avoid Poor/Unclear Type Invariants

Description: In many respects, type design in an OO language is about identifying the logical state of a type (how you describe the type, or the mental model of a programmer using your type), the physical state of a type (the data members that implement that logical state), and a set of invariants on the logical and physical state.

For instance, a type like std::string is logically “a contiguous buffer of characters of length size(), with at least one ‘\0’ character at position size().” Both these conditions can be considered the invariants of string; in other words, these are conditions that must hold at all times. Internally, a string can be represented in various ways by various standard library implementations, but a programmer does not need to know anything about the representation (the physical state) - the type provides an abstraction.

In order to do this, we rely on mechanisms such as data hiding - making data members private so that users of the type cannot arbitrarily change the internals. This is important: if the various pointers and lengths in a std::string were directly accessible and modifiable, it is only a matter of time before someone accesses something inappropriately and breaks our invariants - perhaps we are no longer null-terminated, or perhaps the allocation for our character buffer has been deleted. However, sometimes the invariants of a type are unclear or “poor”, in the sense that objects of the type may reach logical states in which the invariants do not hold. Especially for value types, having unclear invariants or a vague model of what a specific type actually is leads to types that are unnecessarily hard to use.

C++ Example: Many designers argue against “two step initialization.” That is, types that can be constructed separately from becoming usable.
Foo f;  // Constructed, but not useful yet. Must call Init()
if (!f.Init(10)) throw Error(“Failed to initialize!”);
f.Run(); // Do whatever we’re supposed to do.
If we consider this from the perspective of invariants, this becomes clearer. In a two-step initialization design, every function needs to be labelled to describe whether it’s allowable to call that function before calling Init(). In the example above, Run() cannot be called unless the object is initialized using Init. As the class gets bigger, merely documenting which methods are safe to call when becomes more complex - and the odds of users doing it wrong go up.
It’s much better when your type has simpler invariants: if it is constructed, it’s valid.
Foo f(10);  // May throw if initialization failed
f.Run();  // Do whatever we’re supposed to do
Unfortunately, two-step initialization designs are still common, and the resulting types are consistently error prone. For instance, the design of std::fstream shows this design smell: the majority of the API for std::fstream cannot be used after construction, it requires a secondary call to fstream::open().

C++ Example 2: In modern C++, there is also an inverse to two-step initialization. In C++11, the language added support for “move semantics” - an optimization of copying for an object where the source object is known to be unnecessary and can be consumed in the process of moving into the destination object.
std::string s1 = GetString();
std::string s2 = std::move(s1);  // Contents of s1 has been moved into s2
s1.clear();  // s1 still exists, but is in an undefined state.
//You can only safely call methods that have no preconditions/make no assumption about its contents.
In order to avoid adding a “moved-from” state to every type, the language says that a moved-from object is left in a “valid but unspecified” state - the invariants of the type are still upheld, but you cannot reason about the state. This allows the object to be used for operations with no preconditions (you can still call clear() or size() on a moved-from string, but you cannot assume whether or not a call to operator[] is valid).

Moved-from objects and invariants work just like two-step initialization - sometimes people design types where the moved-from state no longer obeys the rest of the type invariants. For instance, a smart pointer that expresses sole ownership (a la std::unique_ptr) and whose content is declared to never be null. When such a type is moved-from (the owned pointer is moved away) the result either violates the sole-ownership invariant or the not-null invariant. Such a NotNullUniquePtr is a common design with broken invariants.

Java Example: Many of the Java cryptography APIs also rely on a two-step initialization. The javax.crypto.Cipher is one such example:
Cipher encryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
encryptCipher.init(Cipher.ENCRYPT_MODE, aesKey);
byte[] cipherText = encryptCipher.doFinal(plaintTextByteArray);
Similar to the C++ example above, calling doFinal() without calling init() will not work. Simply calling getInstance() does not guarantee that the invariants of the type hold. Instead, one has to call init() to initialize the cipher and get an actual cipher object that respects the description of the class: “This class provides the functionality of a cryptographic cipher for encryption and decryption”.

Solution: Be clear what your type is, and document its invariants. Make sure that those invariants are as simple as possible and that they actually hold. Don’t add invalid states - neither at construction nor destruction (nor moved-from).

Lesson 3: Avoid Bad Default Values

Description: To give the developers flexibility in which values they want to specify, and to simplify usage, many APIs come with default values for certain parameters or required fields. In Java, this is typically achieved through providing various overloaded methods or the Builder design pattern. While default values make it easier to create the necessary objects, developers may not be aware of what these defaults are. If the defaults chosen in the API’s design are problematic for any reason, then the default behavior of the API becomes problematic.

Java Example: In the Java Cryptography Extension (JCE) library, which contains Java’s default cryptography support, the default value for the encryption mode when using the popular AES cipher in the javax.crypto.Cipher constructor is the Electronic Codebook Mode (ECB), which is insecure [2]. Thus, client developers who rely on the API’s default values end up using insecure encryption in their applications. Code reviewers might easily miss the problem, because the insecure setting is not visible in the client code. API developers cannot easily fix this problem, because changing the default value would break existing client applications that already encrypted values using the (insecure) default value.

Solutions: Choose reasonable default values for your API. If any default value may become unreasonable (or even critical), consider making it an explicit required parameter. This would at least allow the bad default value to be spotted during code review. Clearly document these default values.

Lesson 4: Avoid Stringly-typed Parameters

Description: A parameter is stringly-typed, if its type is string, but it expects a more specific value that could be more appropriately typed. As a result, client developers cannot make use of many assistance tools, such as static type checkers or completion engines, when programming against the API. This makes the API harder to learn and more easy to misuse.

Java Example: In the Java Cryptography Extension (JCE) library, which contains Java’s default cryptography support, all parameters to instantiate a javax.crypto.Cipher are encoded in a single string parameter that expects a value of the form “//”, where the last or both substrings beginning with “/” may be omitted. It is difficult for client developers to know which values may be passed to this parameter. Moreover, when encountering a valid instantiation, such as:
Cipher cipher = Cipher.getInstance(“AES”);
a client developer cannot see that the parameter value specifies only one of three actual parameters.

Lessons Learned: Use specific types instead of encoding values as strings. Declare separate parameters for separate values, instead of joining multiple values in one string.

Lesson 5: Avoid Incorrect Placement of Functionality

Description: Placing a method on a class where it is unexpected may lead to clients using it in unintended ways.

Java Example: Java’s primitive-type wrapper java.lang.Boolean has a method getBoolean(String). This method returns true if there is a system property with the given name and the value “true”, and false otherwise. Developers might easily confuse this method with parse(String), which converts a string (“true”/”false”) to the corresponding boolean value.
Solution: Place methods on an API where it’s functionality is likely to be expected, e.g., the System class for querying a system property.

Conclusion

Poorly designed APIs can be confusing to client developers, and may lead to potential misuse of the API. In the above, we gave some examples of cases we have personally seen in the past. This is by no means a comprehensive list, and we hope that more developers contribute such examples, which can help in creating a set of design principles for API creators. References

References
[1] M. P. Robillard, E. Bodden, D. Kawrykow, M. Mezini and T. Ratchford, "Automated API Property Inference Techniques," in IEEE Transactions on Software Engineering, vol. 39, no. 5, pp. 613-637, May 2013. doi: 10.1109/TSE.2012.63
[2] Block Cipher Mode of Operation. Wikipedia. https://en.wikipedia.org/wiki/Blockciphermodeofoperation