Credential Security When Working with Remote Collaborators

In this tutorial, I will explain the security issues when working with remote collaborators on projects that require any kind of credentials such as WiFi or any type of confidential information. I will also explain some recommended security layers as well as the solution of best practice recommendations. Additionally, I will show you how to securely handle credentials in development environments and IoT devices.

🔧 Initial Problem

When working on projects with remote collaborators, it is common to share code without exposing sensitive credentials, such as WiFi network credentials. A common mistake is including these credentials in the source code (this sometimes happens because development or testing is faster), but it is a terrible security practice:

const char* DEFAULT_WIFI_SSID = "RedPrivada";
const char* DEFAULT_WIFI_PASSWORD = "ClaveSecreta123";

🚨 Problems with this practice

  1. Credential leakage: If we upload the code to GitHub, anyone with access to the repository can see the network and password.
  2. Difficulty changing credentials: Any change requires modifying the code, recompiling, and uploading the firmware again.
  3. Not scalable: If multiple IoT devices require access, each one needs its own unique configuration.

🚀 Implemented Solution

To solve these problems, a dual approach is chosen:

  1. During development (IoT device connected to the computer): Use environment variables with getenv() to load credentials.
  2. When the IoT device operates independently: Use a secrets.h file, which should be ignored with .gitignore so it is not uploaded to GitHub.

🔨 Secure Code Implementation

1. Setting Environment Variables on the Computer

To keep credentials out of the source code, they should be stored in environment variables.

On macOS/Linux, add the variables in ~/.zshrc (or ~/.bashrc on other systems):

echo 'export WIFI_SSID="RedPrivada"' >> ~/.zshrc
echo 'export WIFI_PASSWORD="ClaveSecreta123"' >> ~/.zshrc
source ~/.zshrc

On Windows (PowerShell):

$env:WIFI_SSID = "RedPrivada"
$env:WIFI_PASSWORD = "ClaveSecreta123"

This way, the code can obtain the values without exposing them on GitHub.

2. Creating the secrets.h File for Use on IoT Devices

For the IoT device to connect to WiFi when not connected to the computer, a secrets.h file must be created:

#ifndef SECRETS_H
#define SECRETS_H

#define WIFI_SSID "RedPrivada"
#define WIFI_PASSWORD "ClaveSecreta123"

#endif

This file is not uploaded to GitHub because it is added to .gitignore:

echo "secrets.h" >> .gitignore

Thus, secrets.h will be present only on the local computer and the IoT device, but never in the repository.

3. Modifying the Code to Use Both Approaches

Now, the code checks if environment variables exist and if not found, uses the values from secrets.h:

#include "wifi_module.h"
#include "secrets.h" // Includes credentials only for standalone IoT device
#include <cstdlib>  // Needed for getenv()

const char* DEFAULT_WIFI_SSID = getenv("WIFI_SSID") ? getenv("WIFI_SSID") : WIFI_SSID;
const char* DEFAULT_WIFI_PASSWORD = getenv("WIFI_PASSWORD") ? getenv("WIFI_PASSWORD") : WIFI_PASSWORD;

void initWiFi() {
    Serial.println("Connecting to WiFi...");
    WiFi.begin(DEFAULT_WIFI_SSID, DEFAULT_WIFI_PASSWORD);

    int wifi_connect_tries = 0;
    while (WiFi.status() != WL_CONNECTED) {
        delay(1000);
        Serial.print(".");
        wifi_connect_tries++;
        if (wifi_connect_tries >= 10) {
            Serial.println("\nFailed to connect to WiFi");
            break;
        }
    }

    if (WiFi.status() == WL_CONNECTED) {
        Serial.println("\nConnected to WiFi.");
        Serial.print("IP Address: ");
        Serial.println(WiFi.localIP());
    }
}

🔒 Security Assessment

Now, the solution protects credentials in different scenarios:

ScenarioRiskImplemented Security
GitHub RepositoryAnyone could see the credentialsCredentials are no longer in the code, they use getenv() and secrets.h is in .gitignore.
Freelancer accesses the repositoryCould see credentialsCannot see secrets.h, needs to set up their own environment.
Someone steals the IoT deviceCould extract firmware to see credentialsIf Flash encryption is configured on the IoT device, memory will be inaccessible.
Compromised computerEnvironment variables could be exposedCould be improved with a more secure secrets manager.

🚀 Conclusion

Now, the project is secure and scalable:

  • During development, use environment variables to avoid exposing credentials.
  • When the IoT device is standalone, use secrets.h (which is not on GitHub).
  • The risk of exposing credentials on GitHub has been eliminated.
  • The remote collaborator can work without seeing the real credentials.

This method allows sharing code with collaborators without compromising security. 🔒🌟

🚀 You can now use this same method to protect your IoT projects or any other environment where sensitive credentials are handled! 🚀