Search Unity

How to use URL handlers and OpenURL safely in your Unity app

, November 6, 2019

The Unity Security team focuses on helping Unity creators build more trustworthy games and applications. Tune in to this blog series for tips, techniques, and recommendations for creating more secure games and apps with Unity.

Today we are launching an ongoing blog series about developing securely with Unity. This series will provide content that Unity developers can apply directly in their games and applications. We hope to cover a variety of topics ranging from basic to advanced knowledge, focused on best practices within using Unity products and services. If there’s a subject you’d like to read about, let us know. We look forward to your feedback. The primary focus of this blog is an overview of URL handlers.

How to use URL handlers and OpenURL safely in your Unity app

URL and file handlers associate file types with the installed program that can open the specified file, but they come with risks. For example, when you’re on your local machine and double-click to open a PDF file from your local drive, your operating system refers to its list of file handlers and selects the program assigned for that file type, so your PDF is opened by a program that can display it correctly. File handlers commonly use the file extension (e.g., .pdf – the suffix at the end of the filename) to decide how to handle the file.

A similar mechanism, the URL handler, decides how to open URLs based on the path prefix. An example of this would be the ubiquitous http:// protocol, which opens your default browser. Another example of a common URL scheme would be file://c:/windows/system32/drivers/gmreadme.txt; entering this URL in the Run dialog will cause Windows to open this license file in Notepad.

URL handlers are a useful feature of your operating system that save users time when launching applications. However, this convenient mechanism may occasionally be unsafe.

Why do URL handlers matter for Unity games?

The Unity Editor and Unity Runtime support programmatic use of URL handlers, both through their use of the .NET Framework, but also through a specific Unity scripting API, namely Application.OpenURL. Game developers often use OpenUrl  so that when a player clicks a link in the game, it launches the local system’s web browser. However, if the game developer does not properly sanitize what is passed into Application.OpenURL, their player could be at risk.

This scripting API is not inherently unsafe, but in any case where untrusted input is used as part of the URL that’s passed in, you need to take care.

Note: Untrusted input

Untrusted input/data is any data that does not come from a trusted source. So then, what is a trusted source? Within the context of this article, only your endpoints with strict HTTPS enabled should be considered trusted. 

There are many examples of untrusted input. If you are designing an anti-cheat system, the player’s local file system should be considered untrusted. If you are developing a multiplayer game, all the players should be considered untrusted. 

There are other ways to protect data/input by leveraging things like public-private key encryption, but those are beyond the scope of this article. (Leave a comment if you’re interested in learning more about this.)

Exploiting URL handling and unsafe usage

While these handlers provide great convenience to users, they carry inherent risks. Here’s an example of unsafe use of Application.OpenURL:

Figure 1. Example of unsafe use of Application.OpenURL

In this example, the in-game commenting system allows users to share links; when a user clicks a link, the VulnerableBrowserClass.OpenBrowser function is called.

Figure 2. Sample scenario with a potentially dangerous link

You can see how easy it is to send an unsuspecting user a link to a potentially dangerous application (Figure 2). If that URL is passed directly to Application.OpenURL, as shown in Figure 1, the victim’s machine will immediately run the application at that link, potentially allowing an attacker to take control of the victim’s system. 

In the image above, the attacker could format the link above to show up as https://SuperLeetCheats.com/VulnTheGame in the chat window, but have the actual link go to their malware at: file://leethaxorz.net/super_malware.exe. The problem here isn’t that users can send each other links; the problem lies in taking the links sent by a user (potentially the attacker) and passing them directly to Application.OpenURL without any validation or sanitization, as seen in the code sample above (Figure 1). Without that sanitization, clicking the link above would cause the Unity Editor to hand the file directly to the target player’s OS, likely resulting in execution of the attacker’s malware. 

How do I mitigate the risk?

The safest way to use Application.OpenURL is to never use it with any untrusted data. Use it only to open URLs that come from your developers or servers, and over a trusted transport (i.e., HTTPS).

If you use remote configurations (e.g., you host a list of content URLs for new updates), then ensure this data is retrieved only via HTTPS, with strict enforcement. Always retrieve remote content in this manner. 

Note: HTTPS won’t fix any vulnerabilities in your app due to untrusted/unsanitized input as described in the attack above. It will, however, ensure the data you send to your player hasn’t been tampered with during transport.

If you’ve decided that you absolutely need to use OpenUrl with data from untrusted sources, then you must do your best to sanitize the input you receive from the untrusted source. There are a few ways to do this, such as with regex pattern matching, building URLs via .Net libraries, or leveraging external sanitization libraries. However, none of these mitigations will work 100% of the time, and no matter what solution you choose, some potential risk is assumed if Application.OpenUrl (and similar functions) is used with untrusted data.

Further, as shown in Figure 2 above, there’s no way for users to know what URL is behind that link. At a minimum, give users a prompt with the full URL they’re about to visit. But you should not consider this a robust solution, as users are known to click through any prompt put in front of them blindly.

Why bother with OpenURL and file handlers?

Using OpenURL and file handlers is very common for developers, particularly with rich media applications and social media-like features, such as in-game chat, reviews, and comments, where users typically want to share content that resides outside the game on the internet. Further, there are common productivity scenarios, such as editing a config file, where you may want to pass a link to the OS, opening the user’s preferred code editing application as a convenience to the user. Application.OpenURL is a platform-independent API to support file handlers, saving Unity developers from having to write their own handlers for every platform.

Is this unique to the Unity Editor and Runtime?

No. As described above, this is a common functionality in most operating systems and is supported by many languages and frameworks. Be mindful of the use of the Windows API Windows.System.LauchURIAsync (for Universal Windows Platform [UWP] apps), or the dreaded System.Diagnostics.Process.Start; both of these native .Net libraries provide the same functionality as Application.OpenURL. LaunchURIAsync allows for launching applications from within Windows’ secure application sandbox, and Process.Start can be used to launch any executable on the local system. Further, some native OS calls provide the same functionality, such as Apple’s open(_:options:completionHandler:). All of these types of APIs can be easily abused if untrusted, unsanitized inputs are passed into these APIs.

What’s next?

We will be posting articles here periodically on topics critical to practicing and maintaining security best practices when developing with Unity. Upcoming topics include secure transport for game data and democratizing the secure software development lifecycle (SSDLC). We’re also working to open source some of our internal guidance and security tooling. 

Is there a security topic you’d like to know more about in a future article? Drop us a line! 

Find out more about Unity Security, including security advisories.

Leave a reply

You may use these HTML tags and attributes: <a href=""> <b> <code> <pre>

  1. It would be great to know more about protecting data inside unity application. How to prevent extraction of models, scripts and configuration files especially for offline installations? How to license unity application to prevent starting on unregistered machine and controlling application distribution? How to create protected communication between Unity application and Operational System Services and Applications. I actually have a lot of security questions and would love to share it:)

    1. I can’t speak directly to preventing extraction of assets, or how licensing in the Editor works, but I do think communication between Unity apps and other services would be a great topic we can cover. We’ll keep this in mind for future blog posts; I think this is a great topic to share with the community.
      Thanks for the feedback Kirill! 👍

      1. Yes, it will be great topic! I just want to clarify. When I said about licensing and preventing extraction I meant extraction of assets, scripts from Unity build and licensing for Unity build. It can be techniques like obfuscation, encryption, authorization, device installation control, etc. When working with B2B segment it is frequent case to protect application and user data.

  2. Quick reminder that System.Diagnostics.Process support for il2cpp would be highly appreciated. We run external plugins using our native C code but would also like to read it’s output, control how it behaves etc but currently we can’t dedicate time making it in C/C++.