OpenMRS Module Release Best Practices

This is intended as a simple checklist and notes for best practices for releases of community-maintained modules.

Internationalization

OpenMRS is used in a large number of different countries all around the world and so it’s important for widely-adopted modules that the user-facing elements are able to be displayed in the appropriate language. This means that we generally do not want to hard-code any display labels, but instead rely on tooling enabled by our various frameworks to display messages in the appropriate language. See this page on the Wiki for how to internationalize the OpenMRS backend, including modules.

Security

Use this section to check your module for common OpenMRS security issues before a release.

Cross-site scripting (XSS)

What Is It?

XSS occurs when data provided by a user is executed as javascript. Detailed explanation: https://owasp.org/www-community/attacks/xss/

Where Does It Occur?

Some frontend frameworks, such as AngularJS, automatically sanitize variables that get displayed on web pages. This is usually pretty good protection, but not necessarily perfect. For example, it’s usually possible to disable the XSS protection features in specific contexts. This has some legitimate use-cases, but could expose your module to XSS attacks.

Other frontend frameworks, such as Java Servlet Pages (.jsp) or the OpenMRS implementation of Grails (.gsp), do not automatically sanitize variables. In this case, it’s necessary for developers to sanitize any variables that contain user input and are displayed on the web page. For example:

Vulnerable! (JSP)

<input type="hidden" name="personType" value="${param.personType}" />

Fixed! (JSP)

<input type="hidden" name="personType" value="<c:out value='${param.personType}'/>"/>

Vulnerable! (GSP)

${config.patient.telephoneNumber ?: ''}

Fixed! (GSP)

${ ui.encodeHtmlContent(config.patient.telephoneNumber ?: '') }

The OpenMRS UI Framework contains several utility functions for sanitizing user inputs (see https://github.com/openmrs/openmrs-module-uiframework/blob/b305971022c9ab0ce2f10b2434aefbd7b70fe462/api/src/main/java/org/openmrs/ui/framework/UiUtils.java). It’s important to use specific encoding functions for specific contexts. For example use encodeHtmlContent() to encode variables that appear within HTML tags, but use encodeHtmlAttribute() to encode variables that appear within HTML attributes.

Deserialization of Untrusted Data

What Is It?

Many deserialization libraries do not guarantee safety. As such, if attackers are able to pass data to these deserializers, they may be able to execute arbitrary code on the underlying operating system. Detailed explanation: https://owasp.org/www-community/vulnerabilities/Deserialization_of_untrusted_data

Where Does it Occur?

There’s potential for exploitation any time a user is able to manipulate data that gets passed into an unsafe serializer. Unsafe serializers include java built-in serialization and Xstream serialization. Double check calls to .readObject() (Java deserialization) and .deserialize (Xstream deserialization) for inputs that could potentially be controlled by a user. It’s almost impossible, or at least exceedingly difficult to sanitize inputs to an unsafe deserializer.