Non-encrypted confidential information
Need
Secure storage, transmission, and encryption of confidential information and credentials
Context
• Usage of Dart 2.0 for building high-performance, cross-platform applications
• Usage of Shelf for managing and organizing data in a Node.js application
• Usage of dart:io for handling input and output operations in Dart programming
• Usage of dart:convert for encoding and decoding data in Dart
• Usage of shelf_router for routing and handling HTTP requests in a Shelf application
Description
1. Non compliant code
import 'dart:io';
import 'dart:convert';
import 'package:shelf/shelf.dart' as shelf;
import 'package:shelf/shelf_io.dart' as io;
import 'package:shelf_router/shelf_router.dart' as shelf_router;
void main() {
final router = shelf_router.Router()...In the above Dart code, we are using the Shelf package, which is a middleware system for Dart server-side applications, with a router that dispatches each scenario to its own handler on `localhost` port `8080`. **Hardcoded credentials and plain-text confidential data.** The `_echoRequest` handler stores confidential information in the variable `confidentialInfo` in plain text, and the username and password are hardcoded as 'admin' and 'password123'. When a request is made, the server responds with the confidential information without any encryption. **Non-encrypted confidential information in the database.** The `readFile`/`writeFile` functions used by the `_dbRequest` handler read and write data to a file without any form of encryption. If an attacker gains access to the file system, they can easily read the contents of the file. **LDAP service credentials in plain text.** The `_ldapRequest` handler establishes an `LdapConnection` whose `bindDN` and `password` parameters are stored in plain text directly in the code. **Non-encrypted confidential information on local devices.** The `_localDataRequest` handler writes confidential Firebase data to a local file named `local.txt` using `writeAsString`, as plain text with no encryption. **Hexadecimal encoding mistaken for encryption.** The `_hexRequest` handler converts confidential information into a hexadecimal string using `toRadixString(16)`. Hexadecimal encoding provides no data protection; anyone who intercepts the response can easily decode it back to the original confidential information. **Non-encrypted API key.** The `_keysRequest` handler stores an API key in the variable `apiKey` in plain text. In all these cases, anyone who gains access to the code or intercepts the server's responses will be able to see the confidential information and credentials in plain text. This is a serious security risk that can lead to data leaks, unauthorized access, and denial-of-service attacks.
2. Steps
• Identify the confidential information and credentials that need to be protected.
• Choose an encryption algorithm suitable for your needs. AES is a commonly used symmetric encryption algorithm.
• Before storing or transmitting the confidential information, encrypt it using the chosen algorithm, for example with the 'encrypt' or 'pointycastle' packages.
• Ensure that the encryption key and initialization vector are securely generated and stored, not hard-coded in the application.
• Remove hard-coded credentials from the source code and store them in a secure and encrypted format in a separate configuration file, a secure secrets management system, or environment variables.
• Ensure that connections to external services such as LDAP use SSL/TLS to encrypt the communication.
• Avoid storing sensitive data directly on the device; if necessary, use secure storage solutions like 'flutter_secure_storage'.
• When the confidential information needs to be used, decrypt it using the same encryption key and initialization vector.
• Implement access controls to restrict who can access the stored data, and implement a secure authentication system such as OAuth or JWT instead of storing credentials in the source code.
• Implement proper error handling and regularly update and patch libraries; do not reveal sensitive information in error messages.
• Use HTTPS for all communications between the client and server to protect data in transit.
3. Secure code example
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:shelf/shelf.dart' as shelf;
import 'package:shelf/shelf_io.dart' as io;
import 'package:shelf_router/shelf_router.dart' as shelf_router;
import 'package:encrypt/encrypt.dart' as encrypt;
import 'package:pointycastle/export.dart' as pc;...The updated code fixes every scenario by encrypting or securely sourcing the confidential information and credentials instead of handling them in plain text. **Hardcoded credentials and plain-text confidential data.** The `encrypt` package is used to encrypt `confidentialInfo` with `Key.fromUtf8`/`IV.fromLength`/`Encrypter(AES(key))` before it is transmitted, and the username and password are retrieved from `Platform.environment` instead of being hardcoded. **Non-encrypted confidential information in the database.** The `pointycastle` library is used to add `encryptData`/`decryptData` helpers based on AES with PKCS7 padding; `writeFile` encrypts data before writing it and `readFile` decrypts it after reading, so the file always holds ciphertext. **LDAP service credentials in plain text.** The hard-coded LDAP credentials are removed and retrieved from environment variables via `Platform.environment`, and `ssl` is set to `true` so the LDAP connection itself is encrypted. **Non-encrypted confidential information on local devices.** The `encrypt` package generates a key and IV and encrypts the Firebase data with AES before it is written to `local.txt`, so the file only ever holds ciphertext. **Hexadecimal encoding mistaken for encryption.** The `crypto` package is used to authenticate the data with HMAC-SHA256 before it is converted to hexadecimal, so decoding the hexadecimal only reveals the encrypted digest, not the original plain text. **Non-encrypted API key.** The API key is removed from the source and read from the `API_KEY` environment variable via `Platform.environment` instead. In every case, the encryption keys, IVs, and secrets used here are simplified for illustration; in a real-world application they should be securely generated, rotated, and stored in a dedicated secrets manager or vault rather than hardcoded.
References
• 020. Non-encrypted confidential information