Main Content

Plain text password stored in file system

Password stored in files in plain text format

Since R2023b

Description

This checker is deactivated in a default Polyspace® as You Code analysis. See Checkers Deactivated in Polyspace as You Code Analysis (Polyspace Access).

This defect occurs when data read from a file is used in functions that expect plain-text passwords. The checker for this issue detects the flow of data from file read functions to the password parameter of functions that take user credentials.

Functions flagged by this checker include the following:

  • Windows® functions such as LogonUserW(), LogonUserA() and CreateProcessWithLogonW(). The third parameter is the password.

  • MySQL functions such as mysql_real_connect() and mysql_real_connect_nonblocking(). The fourth parameter is the password.

Note that the defect checker is not available in the Polyspace user interface and is disabled even if you select the value all for the option Find defects (-checkers). For the issue to be detected, the checker must be enabled explicitly using the option -checkers PLAIN_TEXT_PASSWORD_IN_FILESYSTEM.

Risk

Storing a password in plain-text form in a configuration file is a security risk. Anyone with access to the file can read the passwords and gain access to the password-protected resource.

Fix

Instead of reading passwords from a file system, accept passwords on the fly from standard input.

If passwords have to be stored on the file system, store them in encrypted form. After reading an encrypted password from a file, decrypt the password before use in functions that take user credentials. You can use standard encryption and decryption functions from cryptographic libraries, or write your own functions.

Extend Checker

You can extend this checker by specifying your own password functions or decryption functions.

Suppose you want to specify the following:

  • Function logOnToServer() requires an user name and password.

    void logOnToServer(const char* user, 
                     const char*passwd);

    Suppose the n_pass-th argument of this function is the password. For instance, the second argument in the above signature could be the password.

  • Function decrypt() converts an encrypted password to plain-text form.

    void decrypt(const char* cipher_text, 
                 char* plain_text, 
                 size_t plain_text_size);

    Suppose the n_decrypted-th argument of this function is the decrypted password. For instance, the second argument in the above signature could be the decrypted password.

To make the checker aware of these functions:

  1. In a file with extension .dl, add the following:

    .include "models/interfaces/plain_text_password.dl"
    
    PlainTextPassword.Basic.sensitive("logOnToServer", $InParameterDeref(n_pass-1)).
    PlainTextPassword.Basic.sanitizing("decrypt", $OutParameterDeref(n_decrypted-1)).
    If n_pass and n_decrypted are both 2 (that is, the second parameters of each function are the passwords), then the statements become:
    .include "models/interfaces/plain_text_password.dl"
    
    PlainTextPassword.Basic.sensitive("logOnToServer", $InParameterDeref(1)).
    PlainTextPassword.Basic.sanitizing("decrypt", $OutParameterDeref(1)).
    

  2. Specify this file using the option -code-behavior-specifications. For instance, if the file is named passwordFunctions.dl, use the analysis option:

    -code-behavior-specifications passwordFunctions.dl

Examples

expand all

In this example, the string plain_passwd used as a password with mysql_real_connect() is previously read from a file foo.cfg. If an attacker or malicious user gains access to this file, they can easily access the password-protected resource.

#include <mysql/mysql.h>
#include <stdio.h>
#include <string.h>

#define CONNECT_TO_MYSQL_WITH_PASSWORD(passwd) mysql_real_connect(sql, host, user, passwd, db, 0, 0x0, 0)

extern MYSQL *sql;
extern const char *host;
extern char *user;
extern char *domain;
extern wchar_t *wuser;
extern wchar_t *wdomain;
extern char *db;

int non_compliant_from_file_to_mysql() {
    FILE* fp = fopen("foo.cfg", "r");
    if (fp == NULL) {
        return -1;
    }

    char plain_passwd[64];
    if (fgets(plain_passwd, sizeof(plain_passwd), fp) == NULL) {
        fclose(fp);
        return -1;
    }

    CONNECT_TO_MYSQL_WITH_PASSWORD(plain_passwd);

    memset(plain_passwd, 'X', sizeof(plain_passwd));

    fclose(fp);

    return 0;
}
Correction – Store Encrypted Password in File

Instead of storing passwords in the clear, you can store passwords in an encrypted form. After reading the encrypted password from a file, you can use a decryption function to decrypt the password on the fly. The example below uses a function decrypt() to convert the encrypted password to a plain-text password before using the password with mysql_real_connect().

#include <mysql/mysql.h>
#include <stdio.h>
#includ <string.h>

#define CONNECT_TO_MYSQL_WITH_PASSWORD(passwd) mysql_real_connect(sql, host, user, passwd, db, 0, 0x0, 0)

extern MYSQL *sql;
extern const char *host;
extern char *user;
extern char *domain;
extern wchar_t *wuser;
extern wchar_t *wdomain;
extern char *db;

void decrypt(const char* cipher_text, char* plain_text, size_t plain_text_size);

int non_compliant_from_file_to_mysql() {
    FILE* fp = fopen("foo.cfg", "r");
    if (fp == NULL) {
        return -1;
    }

    char plain_passwd[64], cipher_passwd[64];
    if (fgets(cipher_passwd, sizeof(cipher_passwd), fp) == NULL) {
        fclose(fp);
        return -1;
    }

    decrypt(cipher_passwd, plain_passwd, sizeof(plain_passwd));
    
    CONNECT_TO_MYSQL_WITH_PASSWORD(plain_passwd); 

    memset(plain_passwd, 'X', sizeof(plain_passwd));

    fclose(fp);

    return 0;
}

To make the Polyspace analysis aware of the nature of your decryption function:

  1. Specify the following in a file with extension .dl (for instance, decryptFunctions.dl):

    .include "models/interfaces/plain_text_password.dl"
    
    PlainTextPassword.Basic.sanitizing("decrypt", $OutParameterDeref(1)).
    

  2. Specify the following option with the analysis:

    -code-behavior-specifications decryptFunctions.dl

    See also -code-behavior-specifications.

Result Information

Group: Security
Language: C | C++
Default: Off
Command-Line Syntax: PLAIN_TEXT_PASSWORD_IN_FILESYSTEM
Impact: High

Version History

Introduced in R2023b