Isolated Storage instead of Service Password table

Storing passwords directly in a table is a bad idea from a security point of view. For secure storage of passwords, the Service Password system table was previously used. In Business Central 15.0, it has been removed.

We are offered to use a new data type - Isolated Storage. Here we'll look at a practical example of using this functionality to store passwords securely.
Suppose that we have a table and a setup page, the user should be able to save the password on the page so that it is used by the system somewhere in the process.To do this, we will write three main procedures: SetPassword()GetPassword()GetStorageKey(). Pay attention to the Acces property, it has the value Internal, which will not allow other extensions to access the password. We will also need a secret key in the GUID format by which the password will be stored. You can generate a key in any Online GUID Generator.

In our example, we will use Module DataScope.

table 50000 "General Setup"
{
    DataClassification = CustomerContent;
    Caption = 'General Setup';
    Access = Internal;
    fields
    {
        field(50000; "Primary Key"; Code[10])
        {
            DataClassification = CustomerContent;
            Caption = 'Primary Key';
        }
    }

    keys
    {
        key(PK; "Primary Key")
        {
            Clustered = true;
        }
    }

    procedure SetPassword(NewPassword: Text)
    var
        EncryptionManagement: Codeunit "Cryptography Management";
    begin
        //Delete old password if exist
        if IsolatedStorage.Contains(GetStorageKey(), DataScope::Module) then
            IsolatedStorage.Delete((GetStorageKey(), DataScope::Module));
        //Encrypt password if possible
        if EncryptionManagement.IsEncryptionEnabled() and
         EncryptionManagement.IsEncryptionPossible() then
            NewPassword := EncryptionManagement.Encrypt(NewPassword);
        //Set new password by storage key
        IsolatedStorage.set(GetStorageKey(), NewPassword, DataScope::Module);
    end;

    procedure GetPassword(): Text
    var
        EncryptionManagement: Codeunit "Cryptography Management";
        PasswordTxt: Text;
    begin
        //Check if password exist by storage key
        if IsolatedStorage.Contains(GetStorageKey(), DataScope::Module) then begin
            //Get exist password
            IsolatedStorage.Get(GetStorageKey(), DataScope::Module, PasswordTxt);
            //Decrypt password if possible
            if EncryptionManagement.IsEncryptionEnabled() and
            EncryptionManagement.IsEncryptionPossible() then
                PasswordTxt := EncryptionManagement.Decrypt(PasswordTxt);
            //Return password
            exit(PasswordTxt);
        end;
    end;

    local procedure GetStorageKey(): Text
    var
        StorageKeyTxt: Label '25edcb48-11b9-4e7d-8645-2c95b3156092', Locked = true;
    begin
        exit(StorageKeyTxt);
    end;
}
Besides, we need a page where the user can specify a password.
page 50000 "General Setup"
{
    PageType = Card;
    ApplicationArea = All;
    UsageCategory = Administration;
    SourceTable = "General Setup";
    Caption = 'General Setup';

    layout
    {
        area(Content)
        {
            group(General)
            {
                field(PasswordTxt; PasswordTxt)
                {
                    ApplicationArea = All;
                    ExtendedDatatype = Masked;
                    Caption = 'Password';
                    trigger OnValidate()
                    begin
                        SetPassword(PasswordTxt);
                        Commit();
                    end;
                }
            }
        }
    }

    trigger OnOpenPage()
    begin
        Reset();
        if not Get() then begin
            Init();
            Insert();
            SetPassword('');
        end else
            PasswordTxt := '***';
    end;

    var
        PasswordTxt: Text;

} 

No comments:

Post a Comment