Skip to content

Standard Password Hashing

The WebApp Framework now supports out-of-the-box password hashing.

The cWebSessionManagerStandard class now performs password hashing using the PBKDF2_HMAC_SHA_512 algorithm. This means that if you have not already implemented a hashing algorithm and abstracted the UserLogin and/or other functions, the passwords in the database would be considered “plain text passwords.”

Password hashing is the concept of what some call “one-way encryption.” Unlike encryption, which has a form of decryption, hashing does not. This is useful for passwords because, should a hacker gain access to your database, all user passwords should remain safe for some time if done correctly. Using hashing ensures that even your application does not know the user's password.

When considering password hashing, it is important to choose an algorithm that takes some time, but not too much. This is to ensure that if your database leaks, the hacker must crack the passwords one hash at a time. It is advisable to choose an algorithm that takes around 0.5 seconds.

Why this magic number? In simple terms, this means that a hacker must perform 0.5 seconds of work millions of times to access a single user’s password. While this is somewhat of an exaggeration, the idea is to make all passwords last long enough for users to change their passwords once the hack is uncovered. However, if a hash takes too long, too many simultaneous logins might cause downtime, which is why a good load balancer is essential.

The upgraded cWebSessionManagerStandard class now uses PBKDF2_HMAC_SHA_512 by default. We chose this algorithm to ensure applications are secure enough to be FIPS and NIST compatible, while also being easily deployable out of the box. Developers might wonder why we didn’t use the Security Library instead of this implementation. One reason is that the Security Library is sometimes considered “too difficult.” Additionally, stronger hashing algorithms may require additional dynamic linking libraries (DLLs), which adds to the complexity.

To provide an idea of what algorithms to use, here is an exemplary list based on a normal server system. For accuracy, testing on your own systems is recommended, as these values change as computers become faster:

Hash Speeds

  • Integrity: Use for file/database row integrity.
  • Password: Used for password hashing.
  • Collisions: Indicates that the algorithm is known to have had different inputs resulting in the same hash.

Backwards Compatibility

As mentioned earlier, if you are already using your own version of the SessionManager, that remains a valid choice. This upgrade is not expected to interfere with your custom implementation. However, if you did not implement your own version and never implemented hashing, this might break your login screen, as no user will be valid.

To fix this compatibility issue, you have two choices:

  1. Disable Standard Password Hashing: This option is not recommended. You can disable password hashing by setting pbPasswordHashing to false in the Session Manager Object.

  2. Migrate Plain Passwords: Use the following example business process to migrate your plain passwords:

Use cPasswordHasher.pkg
Use Batchdd.pkg
Use cWebAppUserDataDictionary.dd

Object UpgradePlainPasswords is a BusinessProcess
    Set Process_Title to "UpgradePlainPasswords"

    Object oWebAppUser_DD is a cWebAppUserDataDictionary
    End_Object

    Object oCrypto is a cPasswordHasher
    End_Object

    Procedure onProcess
        Handle hoServer
        String sPassword
        Move oWebAppUser_DD to hoServer
        Send Clear of hoServer
        Send Request_Find of hoServer GE WebAppUser.File_Number 1

        While (Found)
            Get Field_Current_Value of hoServer Field WebAppUser.Password to sPassword
            If (not(CreatePasswordHash(oCrypto, sPassword, &sPassword))) Begin
                Error 8710 "Failed to convert password."
                Procedure_Return
            End
            Set Field_Changed_Value of hoServer Field WebAppUser.Password to ("V1$" + sPassword)
            If (Request_Validate(hoServer)) Begin
                Error 8710 "Failed to validate record."
                Procedure_Return
            End
            Send Request_Save of hoServer
            If (Err) Begin
                Error 8710 "Failed to save record."
                Procedure_Return
            End
            If (Cancel_Check(Self)) ;
                Procedure_Return
            Send Request_Find to hoServer Gt WebAppUser.File_Number 1
        Loop
    End_Procedure
End_Object

Send DoProcess of UpgradePlainPasswords

In addition to Password Hashing, pbSessionCookieHttpOnly has now been set by default to True, as most developers will not have JavaScript libraries that require access to the session cookie. This can further secure your application against XSS attacks. It is still acceptable to turn this off if you experience problems.

As always, we aim to enhance the security of both existing and new applications, which is why we have taken this step. For advice or questions, you can always refer to the forums or support.

Additional Web Security Measures

Here are some additional security measures you can implement to further secure your applications:

  1. pbSessionCookieSecure
    This property is currently turned off to avoid interfering with development. However, we expect most to use HTTPS in production deployments. Therefore, it is advisable to set this property to True. Some browsers may automatically connect to HTTP endpoints if they exist (not all), sending session cookies over an unsecured line. If you only allow HTTPS, it is beneficial to avoid this behavior and secure your users by default.

  2. Content-Security-Policy
    This is one of the many response headers you can specify in IIS. These headers are important and sometimes overlooked, especially if you are a solo Business Developer without a Networking team. One such header is the Content-Security-Policy.

IIS Default Website
IIS HTTP Content Headers

This header specifies where the client's browser is allowed to navigate outside your application and where it can look for resources/content. Setting this can help avoid further exploitation of XSS vulnerabilities.

As of DataFlex 25.0, this is the most minimal policy available. If you use a content delivery network (CDN) for resources like Font Awesome, you will need to make exceptions for that:

default-src 'self' 'unsafe-inline' 'unsafe-eval'
  1. X-Content-Type-Options
    This header is somewhat complex. Browsers sometimes attempt to guess the contents of a downloaded file, such as a JavaScript file, instead of adhering to the Content-Type specified by the server. Setting this header to the value “nosniff” ensures that the browser does not exhibit this behavior and respects the Content-Type header.