Skip to main content

Sensitive information in source code - API Key

Need

Secure storage of sensitive information in source code

Context

  • Usage of Dart for building cross-platform mobile, web, and desktop applications
  • Usage of Shelf for managing and organizing data in Node.js applications

Description

Non compliant code

import 'package:shelf/shelf.dart' as shelf;

void main() {
var apiKey = '1234567890abcdef'; // Sensitive API Key

var handler = const shelf.Pipeline().addMiddleware(shelf.logRequests()).addHandler(_echoRequest);

io.serve(handler, 'localhost', 8080).then((server) {
print('Serving at http://${server.address.host}:${server.port}');
});
}

shelf.Response _echoRequest(shelf.Request request) {
return shelf.Response.ok('Request for "${request.url}"');
}

In the above Dart code, an API key is stored directly in the source code as a plain text string. This is a significant security vulnerability as anyone with access to this source code can see and potentially misuse this sensitive information.

The variable apiKey is declared and assigned a static value. This key is presumably being used to authenticate with some external service, but because it's hardcoded into the application, anyone who can see this source code can also see the key.

This is a problem because API keys are meant to be secret. If someone else gets hold of your key, they can use it to impersonate your application and potentially cause all sorts of problems.

Keeping secrets in source code is a bad practice. It's even worse if the source code is publicly available (for example, if it's shared on a public source control repository). But even if the source code is private, it's still a bad idea to keep secrets in it. For example, someone with legitimate access to the source code might accidentally share it, or it might be exposed in a security breach.

The best practice is to store secrets in a secure location separate from the source code and load them into the application at runtime. For example, you could store the key in an environment variable, or in a secure secrets management service.

Steps

  • Remove the API key from the source code.
  • Store the API key in a secure environment variable.
  • Access the API key in your code using the appropriate method to read environment variables.
  • Ensure that the environment variable is not logged or output in any error messages or logs.
  • Consider using a secrets management service to further secure sensitive information.

Compliant code

import 'dart:io' show Platform;
import 'package:shelf/shelf.dart' as shelf;

void main() {
var apiKey = Platform.environment['API_KEY']; // Securely accessing the API Key

var handler = const shelf.Pipeline().addMiddleware(shelf.logRequests()).addHandler(_echoRequest);

io.serve(handler, 'localhost', 8080).then((server) {
print('Serving at http://${server.address.host}:${server.port}');
});
}

shelf.Response _echoRequest(shelf.Request request) {
return shelf.Response.ok('Request for "${request.url}"');
}

The API key is no longer stored in the source code. Instead, it is stored in an environment variable. This is a more secure method of storing sensitive information, as it is not directly accessible from the source code and can be managed separately from the application itself.

The Platform.environment method is used to access the environment variable. This method returns a map of the current environment variables, and the API key can be accessed using the key 'API_KEY'.

It is important to ensure that the environment variable is not logged or output in any error messages or logs. This is because if the logs are accessed by an unauthorized user, they could gain access to the sensitive information.

For further security, consider using a secrets management service. These services can securely store and manage sensitive information, and can provide additional features such as access control, auditing, and automatic rotation of secrets.

References