At Appcelerator we pride ourselves on our open-source platform and the freedom it gives other developers in the community to review our code. Recently, we were contacted by Sascha Fahl, a security researcher at Leibniz University concerned about some documentation in HTTPClient and the possibility of a man-in-the-middle attack with the default HTTPClient settings.
As of the moment, this is a purely hypothetical attack and we do not have any reports of active exploits, but we want to be proactive when it comes to security. While the upcoming version 3.0 of the Titanium SDK has addressed his concerns, we thought it was a good opportunity to alert the community how to guard against possible attacks on earlier versions of the SDK.
The validatesSecureCertificate property mentioned in the link above controls certificate validation. If validatesSecureCertificate is true, HTTPClient verifies that the server certificate has been signed by a trusted certificate authority, forming a chain of trust all the way back to a “root certificate” on the device. This prevents one site from masquerading as another site using a self-signed certificate.
Titanium supports this property on both iOS and Android. (On Mobile Web, certificate checking is dependent on the browser being used.)
Many developers test their HTTPS code against servers with self-signed certificates, so certificate validation is disabled by default during testing. However, on iOS prior to release 3.0, certificate validation is always disabled by default — that is, you must explicitly enable certificate validation. For reference, this is issue TIMOB-6715.
How to protect yourself
On Titanium SDK 3.0, this property is set to ‘true’ by default on production applications. No action is necessary.For previous SDKs, it is suggested you set it to ‘true’ manually once you are ready to distribute the application. If your test servers have valid certificates, set the property to ‘true’ at all times.
Some independent developers may want to use secure HTTP but be unable to afford the cost of certificate signing. This is not recommended, but it can be supported by setting the property to ‘false’.
Another security-related property provided by HTTPClient on iOS is tlsVersion. In 2011, Apple updated the default Transport Layer Security protocol when using HTTPS. For iOS 4 and lower, HTTPS connections are done via TLS version 1.0 unless otherwise requested. For iOS 5.0 and beyond, these same connections would be done with TLS version 1.2.
For security reasons, when iOS is unable to connect with the requested TLS version, it treats the attempt as a failure instead of retrying with an older version. Unfortunately, many servers do not support TLS 1.2, and while it would be ideal that these servers updated, we understand the need to fall back to TLS 1.0. In iOS Titanium, we try to connect with 1.2, and if it fails, fall back to TLS 1.0. For speed reasons, if this succeeds, we remember the server’s legacy status for the duration of the application session.
- tlsVersion should be used for when you know the level of security your server has.
- If you are uncertain of a server’s TLS support, leave the tlsVersion property blank.
- If you know the server supports only TLS 1.0, you can set this value to TLS_VERSION_1_0 to avoid an unnecessary TLS 1.2 attempt.
- If you know your server supports TLS 1.2, set the value to TLS_VERSION_1_2 for added security, as this denies any attempt to downgrade to 1.0.
Currently, tlsVersion is only supported on iOS. The Android operating system 4.0 and earlier did not have TLS 1.2 support, and most browsers still use TLS 1.0 by default.
Finally, remote images are fetched on separate threads so that the network communications do not block the user interface. Furthermore, requests are coalesced so that multiple requests for the same image do not flood the connection. Because of the nature of image requests, TLS and certificate validation (along with post requests) cannot be done on an individual view basis. If such customization is needed, it is best to fetch the image using HTTPClient and present it to the view as a local file.