Question
· Dec 9, 2020

Best practice for storing secured passwords in objects

Hi-

I have a need to store a password in an object property of a User object.   

What would be best practice for data type assigned to the "Password" property and securing that password against prying eyes, both just browsing the global as well as via SQL?  Better yet, how can I prevent a specific property from being projected to SQL?

Thanks

Product version: IRIS 2020.1
Discussion (2)1
Log in or sign up to continue

What would be best practice for data type assigned to the "Password" property and securing that password against prying eyes, both just browsing the global as well as via SQL? 

Do not store passwords at all. If you need to check passwords hash and salt them - there are enough functions in $System.Encryption to get by. The only exception is when you need credentials to auth against some external system, in that case

  1. Encrypt login/pass.
  2. Store them in a separate encrypted-at-disk DB with separate resource.
  3. Write API to switch into this DB and get your credential, ideally this API returns authenticated object and not the password itself.
  4. Check that it fails for app user.
  5. Use Privileged Routine Application to allow your app access to a separate DB.

Also check Managed Key Encryption - from the docs:

Data-element encryption for applications, also known simply as data-element encryption — A programmatic interface that allows applications to include code for encrypting and decrypting individual data elements (such as particular class properties) as they are stored to and retrieved from disk.

___________

Better yet, how can I prevent a specific property from being projected to SQL?

The best approach is not to store password at all. Still, there are several options:

  • Access management - if the user does not have access to the password column/table he can't access it. InterSystems IRIS supports CLS.
  • Internal - hides property from docs.
  • Private - hides property from SELECT * explorers, but it can still be explicitly referenced by name
  • Custom datatype - redefine getter to return data only to verified callers, for example check Security.Datatype.Password datatype implementation which returns *** instead of actual password value in ODBC context.

Store only hashed passwords... that's all.

Class DC.MyUsers Extends %Persistent
{ 
Property Name As %String;
Property Password As %String;
Property passHash As %String [ Internal, Private, ReadOnly ];
Property passSalt As %String [ Internal, Private, ReadOnly ];
Parameter ITER = 1024;
Parameter LENGTH = 20;
Method PassCheck(psw) As %Boolean
{
  set salt = $system.Encryption.Base64Decode(..passSalt) 
  set hash = $system.Encryption.Base64Decode(..passHash)
  quit $system.Encryption.PBKDF2(psw, ..#ITER, salt, ..#LENGTH)=hash
}
Method PasswordSet(psw) As %Status
{
  // optionally, quality/requirement-check
  if '..pswQuality(psw) quit $$Error^%apiOBJ(5001,"Poor password quality")
  
  set salt=$system.Encryption.GenCryptRand(8)
  set hash=$system.Encryption.PBKDF2(psw, ..#ITER, salt, ..#LENGTH)
  set i%passHash=$system.Encryption.Base64Encode(hash)
  set i%passSalt=$system.Encryption.Base64Encode(salt)
  quit $$$OK
}

Method pswQuality(psw) As %Boolean
{
  quit 1
}
}