Maik Skoddow
Tera Patron
Tera Patron

find_real_file.png

 

 

Introduction

When a user wants to change their password, pre-configured password rules come into effect to enforce the most secure passwords possible. In a baseline installation, the password must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, and one digit. At the "Default" Password Policy (Password Policy > Password Policies) you can choose even stronger rules if the security policies of your company require it.

But unfortunately, there is a "security leak" in ServiceNow, because users with the role "admin" or "user_admin" can store arbitrary passwords in the user records (table sys_user) and thus bypass the password policies.

 

 

Requirement

For users with the "admin" or "user_admin" role, the same password policies should apply when setting a password for records from the sys_use table as apply to all users when they set a new password for themselves during the password forgotten or password change process.

 

 

Solution

For all newer instances the value of the property glide.enable.password_policy is set to "true" (see Documentation). This means that the password policy configured in the "Default" record from table password_policy will be applied.

A nice feature at that record is the "Test Your Password" UI Action which will apply the configured policies to the entered test password:

find_real_file.png 

 

The code of that UI Action is quite simple:

 

// Get the password to be tested.
var testPassword = new GlideEncrypter().decrypt(current.password);

// Check if update is successful or not, if successful, then test the password
var updated = current.update();

if (updated) {
  var isValid = SNC.PasswordPolicyEvaluator.isValidPwdPerPolicy(testPassword);
	
  if (isValid) {
    gs.addInfoMessage(gs.getMessage("Password is Valid."));
  } else {
    gs.addErrorMessage(gs.getMessage("Password is Invalid."));
  }

  action.setRedirectURL(current);
}

 

The only interesting code here is SNC.PasswordPolicyEvaluator.isValidPwdPerPolicy(). The prefix "SNC" indicates a Java-based library you cannot access, but I think it is clear enough what this function call will do.

As you can in the screenshot there is a password field which is of type "Password (2 Way Encrypted)". For this reason it is possible to decrypt the password via new GlideEncrypter().decrypt().

Unfortunately the type of the "Password" field (user_password) at table sys_user is "Password (1 Way Encrypted)". That means the entered value is stored as a secure hash value that cannot be decrypted. So the only chance to get password in plaintext is on client side as on server side the password is already encrypted.

Therefore one part of the solution is a "onSubmit" Client Script that invokes a GlideAjax request for checking the password on a server side Script Include:

NameTestPassword
Tablesys_user
UI TypeDesktop
TypeonSubmit
Script
function onSubmit() {
  var strPassword = g_form.getValue('user_password') || '';

  if (strPassword.length > 0) {
    g_form.clearMessages();
    
    var ga = new GlideAjax("PasswordTester");
    
    ga.addParam("sysparm_name", "testPassword");
    ga.addParam("sysparm_password", strPassword);
    ga.getXMLWait();
    
    var isValid = ga.getAnswer() || '';
    
    if (isValid.length == 0 || isValid == 'false') {
      return false;
    }
  }
}

 

The second part is the mentioned Script Include "PasswordTester":

NamePasswordTester
Client callabletrue
UI TypeDesktop
TypeonSubmit
Script
var PasswordTester = Class.create();

PasswordTester.prototype = Object.extendsObject(AbstractAjaxProcessor, {

  testPassword: function() {
    if (!this.getParameter("sysparm_password")) {
      return false;
    }
    
    var strPassword = this.getParameter("sysparm_password").toString();
    
    return SNC.PasswordPolicyEvaluator.isValidPwdPerPolicy(strPassword);
  },
  
  type: 'PasswordTester'
});

 

You may have noticed that there is no output of error messages. This is because invoking of SNC.PasswordPolicyEvaluator.isValidPwdPerPolicy() also produces exactly the same error messages as if a user wanted to change his own password:

find_real_file.png

 

 

Notes

The above solution is only tested with the System Property glide.enable.password_policy set to "true". If this property is set to "false" then the Installation Exit Script "ValidatePasswordStronger" would be responsible for testing the password policies, but in my PDI that script does not work any more due to thrown exceptions. 

This solution will not work if your instance has an SSO or LDAP integration!

And yes, I am aware that the password is sent to the server in plain text. If this is too insecure, you can use one of the many JavaScript libraries available on the Internet to symmetrically encrypt strings. A corresponding approach can be read in the following article: https://community.servicenow.com/community?id=community_question&sys_id=d0394fe1db5cdbc01dcaf3231f96...

 

Version history
Last update:
‎09-05-2021 07:17 AM
Updated by: