Cybersecurity
DevOps Cloud
IT Operations Cloud
Many organizations need or desire to protect Identity theft, data breaches and online fraud which are becoming more common and sophisticated every day. Beyond traditional authentication mechanism like password-based, organizations are looking for additional protection for employee, partner and customer access to valuable online resources. Organizations desires that, this additional protection should be easy to implement and transparent to the user with positive experience. Solution to this requirement is Adaptive or risk based authentication.
Adaptive authentication will evaluate risk based on set of contextual factors related to access attempt without impacting legitimate user access. This risk-based, adaptive authentication solution will calculate a risk score real-time based on set of rules. Risk evaluate module examines many factors including device identification (finger print), geo location, IPaddress, IPAddress history, known cookie, HTTP headers, user attributes, last login time. If calculated risk score is more than the threshold (allowed) value then step-up authentication, which is two factor authentication is enforced. This provides organizations a transparent layer of protection against identity theft, data breaches and online fraud based user access patterns.
The overall goal of adaptive authentication is to gather available information from the user environment, compare it with a known user profile, and determine if that user needs to step through an additional identification process based on the comparison. Once the user has successfully went through a secondary identification process, the authentication engine needs to remember that the environment from which the user accessed the infrastructure has been verified. Once verified, it should no longer be viewed as a risk as the user has proven identity.
There is a wide array of information that is available to be considered when making this decision.
HTTP Headers,Client IPAddress, Client IPAddress history, Geolocation, Known cookie, Device fingerprint, Lastlogin cookie, User attributes
Above rules are configurable with various options, as explained below
HTTPHeader
HTTP headers received at server based on configuration http header can be used for evaluating the risk factor. The following parameters can be configured:
httpheader.check - enable/disable rule for evaluating risk factor
httpheader.header.names - header names with comma separate for lookup e.g., custom-header, custom-header2
httpheader.header.condition - Logical condition, with javascript syntax. E.g., ((custom-header == "test") || (custom-header2 == "test2"))
httpheader.fail.score - Risk score used on unsuccessful match of header
httpheader.invert.result - Negate the result on successful /unsuccessful match
IPAddress
Checks client IP within allowed IPAddress range can be used for evaluating risk factor
iprange.check - enable/disable rule for evaluating risk factor
iprange.value - IPAddress and IPAddress ranges with comma separate values
iprange.fail.score - Risk score used on unsuccessful match of iprange
iprange.invert.result - Negate the result on successful /unsuccessful match
IPAddress History
Check for IPAddress history of previous logins ipaddress history from user profile attribute
iphistory.check - enable/disable rule for evaluating risk factor
iphistory.size - no of IPAddresses of user previous login to be stored/considered
iphistory.user.attribute - user profile attribute where history is stored
iphistory.save.on.success - on Successful authentication save client IP to history
iphistory.fail.score - Risk score used on failure of iphistory check
iphistory.invert.result - Negate the result of this check
Known Cookie
Check for known cookie
known.cookie.check - Enable/disable rule for evaluating risk
known.cookie.name - Cookie name
known.cookie.value - Cookie value
known.cookie.save.on.success - on successful authentication save the cookie on the client
known.cookie.maxage - Cookie valid time, Optional value, if not defined default value is 172800 seconds
known.cookie.secure - Cookie is secure or not, Optional value
known.cookie.path - Cookie set on path, Optional value
known.cookie.fail.score - Risk score used on failure
known.cookie.invert.result - Negate the result
Device fingerprint
Check the device fingerprint deduced from browser agent.
device.cookie.check - Enable/disable rule for evaluating risk
device.cookie.name - Cookie used to validate the device/system
device.cookie.value.rule - Rule can be prepared with HTTP header names and user attributes defined as global with ‘|’ separator for example, “user-agent|accept|accept-language|accept-encoding|accept-charset|username”
device.cookie.maxage - Cookie valid time, Optional value, if not defined default value is 172800 seconds
device.cookie.secure - Cookie is secure or not, Optional value
device.cookie.path - Cookie set on path, Optional value
device.cookie.save.on.success - On Successful authentication save the cookie on the client
device.cookie.fail.score - Risk score used on failure
device.cookie.invert.result - Negate the result
Last login cookie print
Check the authentication, is from the last used device/system. On successful authentication cookie will be set on device.
lastlogin.cookie.check - Enable/disable rule for evaluating risk
lastlogin.cookie.name - Cookie name
lastlogin.allowed.age - Consider no of days allowed from the same device/system
lastlogin.cookie.maxage - Cookie valid time, Optional value, if not defined default value is 172800 seconds
lastlogin.cookie.secure - Cookie is secure or not, Optional value
lastlogin.cookie.path - Cookie set on path, Optional value
lastlogin.save.on.success - On Successful authentication save the cookie on the client
lastlogin.fail.score - Risk score used on failure
lastlogin.invert.result - Negate the result
User profile attributes
Check the user profile attributes in evaluating the risk factor
profile.check - Enable/disable rule for evaluating risk
profile.attribute.names - User profile ldapAttribute name
profile.attribute.condition - Logical condition in javascript syntax e.g., (username == “testuser2”)
profile.fail.score - Risk score used on failure
profile.invert.result - Negate the result
Geolocation
Check user access location
geolocation.check - Enable/disable rule for evaluating the risk factore
geolocation.countrycode.db.file.path = /opt/novell/nids/lib/webapp/WEB-INF/geo-db-files/GeoIP.dat
geolocation.citycode.db.file.path - data file used for identifying the user location
geolocation.params.check - list of comma separated names to be checked for example countrycodes,regioncodes,regionnames,citys,postalcodes,metrocodes,areacodes
geolocation.valid.countrycodes - Country codes allowed comma separated e.g., US
geolocation.valid.cities - cities allowed comma separated e.g., Provo
geolocation.valid.regioncodes - region codes allowed, comma separated values e.g., UT
geolocation.valid.regionnames - region names allowed, comma separated values e.g., Utah
geolocation.valid.postalcodes - Postal/Zip code allowed, comma separated values e.g, 84606
geolocation.valid.metrocodes - Metro codes allowed, comma separated values e.g, 770
geolocation.valid.areacodes - Area codes allowed, comma separated values e.g, 801
geolocation.fail.score - Risk score used on failure
geolocation.invert.result - Negate the result
Global values for the module
Used across the module in evaluating the risk.
threshold.value - Allowed risk factor
global.risk.handler - Conditional execution of different actions based on total risk factor value. This should be javascript function. Only function body should be changed. E.g., function riskhandler(riskVal){ if(riskVal > 1 && riskVal < 6) return "TWO_FACTOR"; else if(riskVal >= 6) return "DENY_ACCESS"; else return "ALLOW_ACCESS" }
allowed values in javascript return values are, TWO_FACTOR, DENY_ACCESS, ALLOW_ACCESS
global.user.attribute.names - Comma separated user profile ldap attribute names are used in risk values, these are prefetched for rules evaluation e.g, careLicense, username, lastLoginTime,personalTitle
server.nat.enabled - has three values,
true - then header name the below property has to be used to get actual Ipaddress in case L4 or proxy injects this header.
false - Server will get the client IP directly
auto - automatically checks server is behind NAT configuration or not. It will execute amazon api to check public IP of server.
remote.clientip.header.name - if server is behind NAT and L4/proxy injects client IP to custom http header, this header name is used to read actual client IP
remote.clientip.handler - customized class for parsing header value, otherwise default header value is assumed to be one value.
Sample Properties file:
##################
##################
# Risk variables
##################
##################
##################
# IPaddress
#################
iprange.check = true
iprange.value = 137.65.156.1-137.65.156.30,192.168.2.1-192.168.2.32,192.168.5.1-192.168.5.36,137.65.156.68
iprange.fail.score = 1
iprange.invert.result = false
##################
# IPAddress History
##################
iphistory.check = true
iphistory.size = 5
iphistory.user.attribute = personalTitle
iphistory.save.on.success = true
iphistory.fail.score = 1
iphistory.invert.result = false
##################
# Known Cookie
##################
known.cookie.check = true
known.cookie.name = nam-cookie
known.cookie.value = name-cookie-value
#known.cookie.secure = true
#known.cookie.path = /nidp
#known.cookie.maxage = 172800
known.cookie.save.on.success = true
known.cookie.fail.score = 1
known.cookie.invert.result = false
##################
# Device Cookie
##################
device.cookie.check = true
device.cookie.name = device-cookie
# Rule can be prepared with HTTP header names and user attributes defined as global with '|' separator
device.cookie.value.rule = user-agent|accept|accept-language|accept-encoding|accept-charset|username
#device.cookie.secure = true
#device.cookie.maxage = 172800
#device.cookie.path = /nidp
device.cookie.save.on.success = true
device.cookie.fail.score = 1
device.cookie.invert.result = false
##################
# last login cookie
##################
lastlogin.cookie.check = true
lastlogin.cookie.name = lltime
#lastlogin.cookie.secure = true
#lastlogin.cookie.maxage = 172800
#lastlogin.cookie.path = /nidp
# no of days allowed use this cookie
lastlogin.allowed.age = 1
lastlogin.save.on.success = true
lastlogin.fail.score = 1
lastlogin.invert.result = false
##################
# user profile
##################
profile.check = true
profile.attribute.names = username
profile.attribute.condition = (username == "testuser2")
profile.fail.score = 1
profile.invert.result = false
##################
# Geo location
##################
geolocation.check = true
geolocation.params.check = countrycodes,regioncodes,regionnames,citys,postalcodes,metrocodes,areacodes
geolocation.countrycode.db.file.path = /opt/novell/nids/lib/webapp/WEB-INF/geo-db-files/GeoIP.dat
geolocation.citycode.db.file.path = /opt/novell/nids/lib/webapp/WEB-INF/geo-db-files/GeoLiteCity.dat
geolocation.valid.countrycodes = US
geolocation.valid.cities = Provo
geolocation.valid.regioncodes = UT
geolocation.valid.regionnames = Utah
geolocation.valid.postalcodes = 84606
geolocation.valid.metrocodes = 770
geolocation.valid.areacodes = 801
geolocation.fail.score = 1
geolocation.invert.result = false
##################
# HTTP request header name-value
##################
httpheader.check = true
httpheader.header.names = custom-header,custom-header2
httpheader.header.condition = ((custom-header == "test") || (custom-header2 == "test2"))
httpheader.fail.score = 1
httpheader.invert.result = false
#aa.geolocation2 = com.netiq.custom.adaptive.auth.impl.GeoLocationCheckerImpl
##################
# global values
##################
global.user.attribute.names = carLicense,username,lastLoginTime,personalTitle
remote.clientip.header.name = clientIP
#process clientIP header value
#remote.clientip.handler = com.netiq.custom.ClientIPParser
#values for server is behind NAT server are, true false auto
# Value auto is programmatically getting external IP and comparing with local IP,
# if not matches server is considered to be behind NAT server
server.nat.enabled = false
#Risk Threshold value
thresold.value = 1
global.risk.handler = function riskhandler(riskVal){ if(riskVal > 1 && riskVal < 6) return "TWO_FACTOR"; else if(riskVal >= 6) return "DENY_ACCESS"; else return "ALLOW_ACCESS" }
Geo Location data files:
Note: This cool solution uses Geolite data created by MaxMind available at http://www.maxmind.com
Check license, above are free for development. In case different geo databases are planned to be used, then custom geolocation parser need to be implemented. Check the section extensions below.
Extensions:
New rule in risk calculation:
Extend this CheckBase.java base class to implement custom adaptive authentication rules
Add this new class to properties file as aa.<<name>> = <<class full name>>
E.g.,
aa.geolocation2 = com.netiq.custom.adaptive.auth.impl.GeoLocationCheckerImpl
Add required properties in properties for this new rule
New Client IP parser:
Implement the interface com.netiq.custom.adaptive.auth.util.ClientIPInf and provide parse method.
Add this parser to properties file, the property remote.clientip.handler = com.custom.handler.clientIP
Note:
If any java version related error shows up in logs, recompile the source with proper JRE
NAM4 and 3.2.2 is Java 7, before this it is Java 6
Please share your comments!!