Using Persistent Cookies for Browser Device Registration with ISAM Advanced Access
Technical Overview
Many customer enquiries (How do I…..?) related to IBM Security Access Manager and associated technologies cross my path, and I often find it intriguing and a good old-fashioned challenge to try and figure out how to solve some of these problems with our technology. The solution in this article is one I developed a couple of years ago with TFIM and the risk-based access technology, however it is equally applicable to ISAM for Mobile in ISAM 8, and now Advanced Access Control in ISAM 9.
The basic premise of the problem is to use a persistent cookie as a mechanism to tag a browser (i.e. “register a device” in ISAM context-based access terminology), such that a user needs to perform step-up to strong authentication on first authentication from a new browser, or one where cookies have been deleted, and thereafter from the same browser only a lower level of authentication needs to be performed. This is common across many internet websites, often recognizable by checkboxes on the login screen with labels like “Check this box if you are [not] using a public or shared computer”. The boolean logic is often confusing as the question is really asking you to tell the website if you are using a device that is personal to you to determine if it is safe to drop a persistent cookie on it tied to your account.
Logically, the workflow being implemented looks like this:
Pre-requisite knowledge for this article
This article is not going to introduce context-based access configuration in ISAM. That topic is the subject of a fairly comprehensive ISAM for Mobile Cookbook. Instead I will simply demonstrate what changes you would need to make to an already-configured scenario from that cookbook to modify the device registration capabilities from a set of javascript-collected browser attributes and headers (the standard “Browser” risk profile), to a new risk profile based entirely on the presence of a persistent cookie that the browser will be tagged with.
As a quick recap of where we begin this story, context-based access is already configured with the standard “Browser” risk profile and info.js. The info.js is a piece of javascript embedded in a page that the browser loads. In the case of the Mobile Cookbook, info.js is loaded in the <head> section of pages that are included in the demonstration application that ships with the ISAM appliance. We can see this in a view-source of the main page of the demo application (some lines removed for brevity):
<head>
...
<script src="/mga/sps/ac/js/info.js"></script>
...
</head>
The purpose of the info.js is to collect attributes from the browser and send them to the attribute collector endpoint of the ISAM server as “context-based session attributes”. There are several important points to note about info.js and how this step works:
- The execution of info.js must occur prior to any policy evaluation which relies on data from these collected session attributes. As such it is often embedded into a login form, with the fields of the login form stuffed into a hidden <div> which is only made visible once the asynchronous result of the sendSession() ajax call from info.js completes. That is NOT the case in the Mobile Cookbook demo, instead the info.js is simply embedded in the head section of pages of the demo application.
- When info.js submits data to the attribute collector, the data is indexed by a “session index”. The value of this session index by default comes from a cookie called ac.uuid which is generated by info.js itself. In the Mobile Cookbook you are guided through steps to change the attribute collector session index from the auto-generated ac.uuid cookie to the PD-S-SESSION-ID cookie – i.e. the cookie used by WebSEAL itself for browser sessions. This is ok for the demo, however you need to know that the PD-S-SESSION-ID cookie value changes when you transition from an unauthenticated to an authenticated state. Therefore if you were going to embed info.js in an unauthenticated login page as suggested in my previous point, you should not use PD-S-SESSION-ID as your attribute collector session index, since it will not be the same value post-authentication.
- The set of attributes that info.js is able to collect will vary from browser-to-browser and computer-to-computer based on a variety of things often out of your control such as browser security settings, mobile phone operating systems, etc. Therefore it is often hard to arrive at a universal set of always-available properties that can be collected via javascript to suit all standard browsers. It has also been noticed that some attributes which are almost always present (such as User-Agent header) are often not suitable for use as a device registration attribute because their value changes too often (e.g. with browser updates). In fact it was this very problem that lead to my decision to switch to using a persistent cookie as a browser tagging mechanism in the first place.
Let’s now take a look at the standard Browser risk profile in the appliance and see what attributes it is using for device registration and comparison. This screenshot comes from the Secure Access Control -> Risk Profiles management page of the appliance:
Notice that there are six different attributes that comprise this risk profile, and that they have different relative weight that will be factored in when computing a risk score to “match” whether or not the attributes supplied by info.js within a particular session line up with stored attributes from a previous device registration. When these attributes change frequently (for the same browser), or when the particular browser platform is unable to supply them, then undesirable end-user experiences (such as excessive prompting for strong authentication credentials) can occur. It is this motivation that led to the development of this article to show you how to use a simple persistent browser cookie as a replacement device registration mechanism.
Finally, for completeness, let’s inspect the policy that is attached to the Risk-based Access Scenario page in the demonstration application:
This policy basically says if you are not currently using a known registered device, then perform strong authentication followed by silent device registration. If you are using a known registered device (evidenced by a low riskScore), then you will be granted access. If you are paying close attention, you might notice my example is using TOTP for strong authentication instead of HOTP as described in the mobile cookbook, however that difference is irrelevant for the purposes of this article. What is also interesting is that NO CHANGES will be required to the policy used in this example. All that we will be modifying is the attributes used for device registration and recognition.
Let’s now set about making the updates necessary to use a persistent cookie for device registration.
Modifying the info.js
First let’s take a look at the info.js script. This can be found on your appliance by navigating to Secure Access Control -> Template files, as shown:
Download the file, study it, and understand that the real action happens when the sendSession() method is called to initiate an ajax call with as many of the standard browser attributes populated as the info.js is able to gather.
I will now show you the modifications that need to be made to generate and include a persistent cookie for browser tagging:
Near the top fo the file, where all the variables are declared, add these lines:
var fingerprintCookieName = "browserFingerprint"
var fingerprintCookieValue = getFingerprintCookie();
function generateRandom(len) {
// generates a random string of alpha-numerics
var chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
var result = "";
for (var i = 0; i < len; i++) {
result = result + chars.charAt(Math.floor(Math.random()*chars.length));
}
return result;
}
function getFingerprintCookie() {
var fingerprint = getCorrelationID(fingerprintCookieName);
if (fingerprint == null || fingerprint.length < 1) {
// generate a new random fingerprint
fingerprint = generateRandom(50);
var exp = new Date ();
exp.setFullYear(exp.getFullYear()+20);
var cookieDef = fingerprintCookieName + "=" + fingerprint + ";path=/;secure;expires=" + exp.toGMTString();
document.cookie = cookieDef;
}
return fingerprint;
}
Further down in the file, within the sendSession(timesCalled) function, add the code shown between the BEGIN and END comments below. Other code before and after is shown for context to help you find where to insert the population of the fingerprintCookie attribute:
if((typeof deviceFonts != "undefined")&& deviceFonts){
jsonObj['deviceFonts'] = fontList;
}
//
// BEGIN - added to insert fingerprint cookie in session
//
if((typeof fingerprintCookieValue != "undefined")&& fingerprintCookieValue){
jsonObj['fingerprintCookie'] = String(fingerprintCookieValue);
}
//
// END - added to insert fingerprint cookie in session
//
if(window.XMLHttpRequest) {
ajaxRequest = new XMLHttpRequest();
} else {
ajaxRequest = new ActiveXObject("Microsoft.XMLHTTP");
}
What these changes have done is generate and store (if not already found on the browser) a persistent cookie whose value is made up of 50 random alphanumeric characters. The cookie value is supplied to the attribute collector using the attribute name fingerprintCookie.
Next we need to look at modifying the known attributes and risk profile to make use of this newly-supplied attribute.
Adding a new fingerprintCookie attribute
In order to use the fingerprintCookie in a risk profile and for device registration, we need to declare it and state its purpose. Navigate to Secure Access Control -> Attributes, and add a new fingerprintCookie attribute as shown:
Notice in particular that the attribute is marked for use as both a Session attribute, and a Device attribute, meaning that it will be stored as part of device registration if used in a policy that performs silent or consent-based device registration, where the active risk profile contains this attribute.
Creating a new risk profile using the fingerprintCookie attribute
Finally we need to change the active risk profile to use the fingerprintCookie attribute instead of the current collection of attributes used in the Browser profile. In the administration console, navigate to Secure Access Control -> Risk Profiles, and create a new Risk Profile called BrowserFingerprintCookie, with the fingerprintCookie attribute included with a non-zero weight.
Be sure to make your new risk profle the Active profile.
Notice that my risk profile also includes the browserPlugins and deviceFonts attributes, but with zero weight. This technique can be used to include them in the stored device fingerprint, but not use them in calculations for the riskScore – i.e. they have no practical meaning when it comes to recognizing a device. Why would you want to do this? Well, the main reason I included them is so that later I can statistically mine the set of all registered devices to look for patterns in the types of browsers being used. This might be helpful, for example, to see how many iPhone vs Android users you have on mobile devices. It’s quite ok however to leave them out and have only the fingerprintCookie attribute in the risk profile.
Testing and understanding the solution
Using a browser navigate to the main mobile demonstration page, and authenticate with username and password as a regular user. At this point info.js should run, and if you use Firefox Firebug, or Chrome Developer Tools to inspect current cookies, you should see that a new persistent cookie has been created called browserFingerprint, as shown here:
Next, navigate to the Risk-based Access Scenario link on the demonstration application. This is a URL where the policy is attached. As the browser is not currently registered, you should be forced to provide strong authentication via one-time-password. Complete strong authentication, and should see the simple landing page shown:
You can inspect your current credential using the diagnostics page of the demonstration application, and observe that it includes an attribute used in the policy to indicate you have performed one-time-password authentication in this session:
You can also navigate to the Profile -> Manage registered devices page, and observe that you now have a registered device (completed as part of silent device registration in the policy) which includes your fingerprintCookie attribute:

Finally, you can shutdown and restart the browser (or logout by accessing /pkmslogout), and repeat the entire scenario and notice that on second visit you do not have to provide one-time-password authentication. To prove that it is the browserFingerprint cookie that is being used to recognize your browser, use your browser settings page to delete just this persistent cookie and re-run the scenario. This time you will need to provide one-time-password authentication again.
Security Recommendation
It is recommended that in ISAM 9.0+ versions that support it, that the device attributes be stored hashed on the server rather than in plain text. This prevents reconstruction of the fingerprint cookie from the hash. For more information on this setting see: https://www.ibm.com/support/knowledgecenter/SSPREK_9.0.0/com.ibm.isam.doc/admin/task/rbaAdminHashAlgorithm.html
Summary
There is a lot of flexibility in the advanced access capabilities of ISAM, including flexibility in the way devices are registered and recognized to provide intelligent and selective strong authentication challenges. In this article I have presented one simple device registration pattern using a persistent cookie to “tag” the browser instead of trying to subtly use attributes mined from the browser with javascript. This technique was used in real scenarios that I have deployed to work around issues where the userAgent header was changing frequently on the browsers being used, mostly due to vendor browser updates.
I hope you find the scenario useful, and that the information provided in this article improves your own understanding of how context-based access works on the ISAM appliance. As always, feel free to drop me a line if you have an ISAM-related scenario you are struggling to implement.