# Modules.Https
Prevents a man-in-the-middle attack when used with the Titanium.Network.HTTPClient
class.
# Overview
You can download the module at appcelerator.https (opens new window)
Use the HTTPS module to create a Security Manager for Titanium.Network.HTTPClient
that authenticates a set of HTTPS servers by pinning an HTTPS server's URL to its
public key contained in the certificate.
The X.509 certificate files can have any name and extension you wish, but they must be in DER binary format.
The security manager will guarantee that all HTTPClient
connections to this URL
are to a server that holds the private key corresponding to the public key embedded in the
certificate, therefore authenticating the server and preventing man-in-the-middle attacks.
# Concepts
Typically, HTTPS connections are authenticated using a chain of trust, where the identities of various intermediate certificate authorities (CA) are checked until a trusted root CA can be authenticated.
For example, an intermediate CA signs the HTTPS server's certificate used to check the identity of the HTTPS server you want to connect to. However, the intermediate CA cannot be trusted until its identity is verified. The certificate of the intermediate CA must be checked to see if the CA is trusted. This process repeats until a root CA can be checked. Once all identities have been validated, the application can establish a secure connection to the HTTPS server. This mechanism is known as a certificate chain.
This mechanism relies on trusting third parties to carefully check and validate other companies that sign certificates. If an untrustworthy CA issues a valid certificate to an attacker or an attacker gets a hold of a CA's private key, the attacker can insert themselves into the certificate chain, then intercept and send data to the client. This is known as a man-in-the-middle attack.
To prevent man-in-the-middle-attacks, the security manager,
created by this module, ensures that the public key in the leaf certificate (or other certificate identified
by the trustChainIndex
property) of the chain is the same as the public key in the certificate configured
with this URL. If the public keys match, the chain is passed onto the underlying OS to authenticate.
If they do not match, the connection is terminated.
Since we pass the chain to the underlying OS to validate, self-signed certificates will be rejected.
Note that the validatesSecureCertificate
property of the HTTPClient
is not honored for pinned URL's.
For the Security Manager to participate in the connection, the initial URL must be configured.
If a connection redirects to a different host, then public key validation on the redirected URL will only be performed if that URL is also configured in the Security Manager. If the redirected URL is not configured, then the default OS authentication is triggered.
# Getting Started
Once you have installed the module and added it as a depedency and
use require()
(ES5) or import
(ES6+) to access it from JavaScript:
// ES5
var https = require('appcelerator.https');
// ES6+
import 'https' from 'appcelerator.https';
The https
variable is a reference to the module object. Use this reference to call the
createX509CertificatePinningSecurityManager()
method to authenticate the specified HTTPS URLs.
Pass in an array of dictionaries as the only required parameter to the method. Each
dictionary in the array contains three keys (two of them required):
url
: URL of the server to contact. Can be a fixed URL or wildcard URL (if supported by the certificate)serverCertificate
: X.509 certificate in DER format to verify the server's identitytrustChainIndex
: (Optional) index of the trust-chain certificate to validate against (default: 0 - leaf certificate).
For example:
var securityManager = https.createX509CertificatePinningSecurityManager([
{
url: 'https://www.example.com',
serverCertificate: 'exampleServerCertificate.der',
trustChainIndex: 0
}
]);
After the security manager is created, create an HTTPClient
object and set the
Titanium.Network.HTTPClient.securityManager property to the security manager
object you just created. You must set this property when creating the HTTPClient
instance.
var httpClient = Ti.Network.createHTTPClient({
onload: function(e) {
Ti.API.info('Received text: ' + httpClient.responseText);
},
onerror: function(e) {
Ti.API.error(e.error);
},
timeout: 5000,
// You can only set this property when creating the HTTPClient
securityManager: securityManager
});
After the securityManager
property is set, call the HTTPClient
's open()
and send()
methods to initiate the HTTPS request.
httpClient.open('GET', 'https://example.com');
httpClient.send();
If the authentication fails, a security exception is thrown. The HTTP client's onerror
callback will be passed an error object with the code
key set to -1
and the message
key
set to the following message:
`Certificate could not be verified with provided public key`
To perform another HTTPS request, you need to create another HTTPClient
object and follow the
same procedure to initiate an HTTPS request. You can reuse the same security manager object.
# Examples
# Simple Example
This example pins two URLs.
The first URL, https://dashboard.appcelerator.com, is pinned to the
public key in the X.509 certificate, named appcelerator.com.pem
, located in the
application's Resources
directory (Classic) or app/assets/
directory (Alloy).
The second URL, https://www.wellsfargo.com, is pinned to the public
key in the X.509 certificate, named wellsfargo.der
, located the application's
Resources
directory (Classic) or app/assets/
directory (Alloy).
// Require in the module
var https = require('appcelerator.https'),
securityManager,
httpClient;
// Use the module to create a Security Manager that authenticates the specified URLs
securityManager = https.createX509CertificatePinningSecurityManager([
{
url: 'https://dashboard.appcelerator.com',
serverCertificate: 'dashboard.appcelerator.com.der'
},
{
url: 'https://www.wellsfargo.com',
serverCertificate: 'wellsfargo.der'
}
]);
// Create an HTTP client the same way you always have
// but pass in the optional Security Manager that was created previously.
httpClient = Ti.Network.createHTTPClient({
onload: function(e) {
Ti.API.info('Received text: ' + httpClient.responseText);
},
onerror: function(e) {
Ti.API.error(e.error);
},
timeout: 5000,
// Set this property before calling the `open` method.
securityManager: securityManager
});
// Prepare the HTTPS connection in the same way you always have
// and the Security Manager will authenticate all servers for
// which it was configured before any communication happens.
httpClient.open('GET', 'https://dashboard.appcelerator.com');
// Send the request in the same way you always have.
// Throws a Security Exception if authentication fails.
httpClient.send();
# Properties
# apiName READONLY
The name of the API that this proxy corresponds to.
The value of this property is the fully qualified name of the API. For example, Titanium.UI.Button
returns Ti.UI.Button
.
# bubbleParent
Indicates if the proxy will bubble an event to its parent.
Some proxies (most commonly views) have a relationship to other proxies, often established by the add() method. For example, for a button added to a window, a click event on the button would bubble up to the window. Other common parents are table sections to their rows, table views to their sections, and scrollable views to their views. Set this property to false to disable the bubbling to the proxy's parent.
Default: true
# lifecycleContainer
The Window or TabGroup whose Activity lifecycle should be triggered on the proxy.
If this property is set to a Window or TabGroup, then the corresponding Activity lifecycle event callbacks will also be called on the proxy. Proxies that require the activity lifecycle will need this property set to the appropriate containing Window or TabGroup.
# Methods
# addEventListener
Adds the specified callback as an event listener for the named event.
Parameters
Name | Type | Description |
---|---|---|
name | String | Name of the event. |
callback | Callback<Titanium.Event> | Callback function to invoke when the event is fired. |
Returns
- Type
- void
# applyProperties
Applies the properties to the proxy.
Properties are supplied as a dictionary. Each key-value pair in the object is applied to the proxy such that myproxy[key] = value.
Parameters
Name | Type | Description |
---|---|---|
props | Dictionary | A dictionary of properties to apply. |
Returns
- Type
- void
# createX509CertificatePinningSecurityManager
Creates a Security Manager object for the HTTPClient
to authenticate a specified set of HTTPS URLs.
Set the object returned by this method to the securityManager
property to authenticate the connection. Pass the object to the securityManager
property when creating
the HTTPClient
instance.
Parameters
Name | Type | Description |
---|---|---|
params | Array<Dictionary> | Server URLs with the corresponding certificate to authenticate, specified as an array of dictionaries that must contain the following keys:
Optionally, use the following key for further configuration:
|
Returns
# fireEvent
Fires a synthesized event to any registered listeners.
Parameters
Name | Type | Description |
---|---|---|
name | String | Name of the event. |
event | Dictionary | A dictionary of keys and values to add to the Titanium.Event object sent to the listeners. |
Returns
- Type
- void
# removeEventListener
Removes the specified callback as an event listener for the named event.
Multiple listeners can be registered for the same event, so the
callback
parameter is used to determine which listener to remove.
When adding a listener, you must save a reference to the callback function in order to remove the listener later:
var listener = function() { Ti.API.info("Event listener called."); }
window.addEventListener('click', listener);
To remove the listener, pass in a reference to the callback function:
window.removeEventListener('click', listener);
Parameters
Name | Type | Description |
---|---|---|
name | String | Name of the event. |
callback | Callback<Titanium.Event> | Callback function to remove. Must be the same function passed to |
Returns
- Type
- void