FortiManager
FortiManager supports network operations use cases for centralized management, best practices compliance, and workflow automation to provide better protection against breaches.
sjanssens
Staff
Staff
Article Id 419702
Description This article describes the impacted API performance on FortiManager versions 7.2.11, 7.4.7, 7.6.3, and higher. An explanation is provided, and some suggestions to improve API applications.
Scope FortiManager running versions 7.2.11, 7.4.7, or 7.6.3 and higher.
Solution

Introduction:

Passwords of users of applications like FortiManager need to be protected, as a leak of credentials can lead to unexpected behavior. In order to save passwords securely in the database, it will not save the password itself but rather the hash value of it, so when a new login attempt is made, it will run the hashing algorithm and then compare the result with the value in the database to see if there is a match. If there is a match, the correct password has been entered.

 

Changes implemented:

In versions 7.2.11, 7.4.7, and 7.6.3 of FortiManager, the SHA256 hashing algorithm has been replaced with the PBKDF2 hashing scheme with randomized salts for enhanced password security. This shows up in the relevant admin guide sections:

 

This has implications for the performance of logins as well as for any APIs (which require authentication as well). The PBKDF2 hashing scheme is slow by design because it is meant to be used for passwords. The process involves multiple iterations, meaning that the function is executed repeatedly. That makes it harder for attackers to run a fast dictionary attack. Before, when using SHA256, it was fast and allowed for efficient brute-force attempts, as it was very quick to calculate the hash value to compare against the database.

 

Problem Description:

The changes in the password security have an implication that when running API calls, it is a must to try to minimize the amount of time/cycles that are spent on the authentication itself. 

 

API requests can be authenticated in two different ways:

  1. Session based authentication
  2. Token based authentication

 

When using session-based authentication, the flow for API calls is high-level as follows:

  1. Login request with username and password, where a session key is provided in response (different each time).
  2. Make API requests using the session key from step 1.
  3. Logout request with the session key to terminate the session.

 

When using token-based authentication, the flow for API calls is high-level as follows:

  1. At the time of creation of the API user, it generates a permanent API key (this can be renewed, but does not need to).
  2. Make API requests using the API key from step 1.

 

For example, when a script using API calls would create 100 dynamic interfaces on FortiManager, then from tests following results come out:

 

  Before change After change
Session based (incl. login/logout) 33 seconds 34 seconds
Token based 32 seconds 1 minute 44 seconds

 

The token-based authentication has the biggest impact of the change of authentication mechanism because every single request (out of the 100) is reviewed with the slow PBKDF2 hashing scheme, while for session-based authentication, the authentication only happens on the login request and not anymore on the next 100 requests because it just utilizes the session key. Therefore, the impact of the slower authentication is only minor.

 

Note: session-based authentication has some drawbacks as well because if the script launching the API calls fails, it does not log out the user, and the session remains active.

 

Potential Solutions and Improvements:

At this point in time, the suggestion is to utilize session-based authentication for any scripts launching API calls if performance matters. Make sure to run multiple API calls under the same session so the number of logins is reduced. A useful Python library that can be used to make sure that the user is logged out when the script fails can be found on https://pypi.org/project/pyfmg/.

 

If token-based authentication is required, then the following recommendations are applicable, as session-based authentication often requires frequent regeneration, adding extra API calls and latency (because of the login again):

  • Follow the API Best practices:
    • Limit request frequency.
    • Cache data,
    • Use multiplexing to regroup multiple APIs into a single request.
    • Etc.

  • Use the very first API user created, as the order is important because the password check goes over the list of API users sequentially, and therefore, the time for authentication on the last user is a lot larger than that of the very first user.

  • Make parallel requests on the API instead of sequential (if possible). However, be aware of bug 1080282 (fixed in v7.6.2 and higher), where concurrent token-based authentication requests can lead to a 'no permission' error.