Non-encrypted confidential information - Base 64 - Scala

Non-encrypted confidential information - Base 64 - Scala

Need

Secure storage of confidential information

Context

  • Usage of Scala for building scalable and high-performance applications
  • Usage of play.api.libs.json.Json for JSON parsing and serialization in Play Framework
  • Usage of play.api.mvc._ for handling HTTP requests and responses in Play Framework
  • Usage of play.api.libs.json.JsValue for handling JSON data in Play Framework

Description

Non compliant code

        import play.api.libs.json.Json
import play.api.mvc._
import play.api.libs.json.JsValue

class CredentialsController @Inject()(cc: ControllerComponents) extends AbstractController(cc) {

  def storeCredentials = Action(parse.json) { request =>
    val credentials: JsValue = request.body
    val base64Credentials: String = (credentials \\ "base64Credentials").as[String]
    // Store base64Credentials somewhere in the system
    // ...
    Ok(Json.obj("status" -> "ok"))
  }
}
        
        

In the code snippet above, we have a Scala backend application using the Play framework. The application has a controller named CredentialsController. This controller has a method storeCredentials, which accepts JSON data from the request body.

The method retrieves the base64 encoded credentials from the request body with (credentials \\ "base64Credentials").as[String] and then proceeds to store these credentials somewhere in the system.

The vulnerability lies in the fact that these credentials are stored as base64 encoded strings. Base64 is not an encryption method but an encoding scheme. It is used to convert binary data into text format. The encoding is easily reversible, which means that anyone who has access to the base64 encoded credentials can easily decode them and get the original credentials.

Storing sensitive data in base64 format in the source code exposes the data to anyone who can access the code. This is a severe security vulnerability as it can lead to unauthorized access to the system, data breaches, and other security issues.

Steps

  • Do not store confidential information, such as credentials, in the source code.
  • Use a secure storage mechanism, such as a database or a secure key vault, to store confidential information.
  • Encrypt the confidential information before storing it.
  • When receiving the credentials in the request, ensure that they are transmitted over a secure channel, such as HTTPS.
  • Avoid using Base64 encoding for storing sensitive information. Instead, use strong encryption algorithms.
  • Consider using a secure authentication mechanism, such as OAuth or JWT, instead of storing credentials directly.

Compliant code

        import play.api.libs.json.Json
import play.api.libs.json.JsValue
import play.api.mvc._
import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec
import java.util.Base64
import play.api.Configuration

class CredentialsController @Inject()(cc: ControllerComponents, config: Configuration) extends AbstractController(cc) {

  private val encryptionKey = config.get[String]("encryption.key")

  def storeCredentials = Action(parse.json) { request =>
    val credentials: JsValue = request.body
    val base64Credentials: String = (credentials \\ "base64Credentials").as[String]
    val encryptedCredentials = encrypt(base64Credentials, encryptionKey)
    // Store encryptedCredentials somewhere in the system
    // ...
    Ok(Json.obj("status" -> "ok"))
  }

  private def encrypt(strToEncrypt: String, secret: String) : String = {
    val cipher: Cipher = Cipher.getInstance("AES/ECB/PKCS5Padding")
    cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(secret.getBytes("UTF-8"), "AES"))
    Base64.getEncoder.encodeToString(cipher.doFinal(strToEncrypt.getBytes("UTF-8")))
  }
}
        
        

The updated code now includes encryption of the credentials before storing them. The encryption key is stored in the application's configuration and not in the source code. This key should be securely managed and not exposed in the source code or version control system.

The encrypt function uses AES encryption with ECB mode and PKCS5 padding. It encrypts the credentials using the provided secret key. The encrypted credentials are then Base64 encoded before being returned. This ensures that the stored credentials are not in plain text and are not easily decipherable.

The storeCredentials function now calls the encrypt function to encrypt the credentials before storing them. This ensures that even if the stored credentials are accessed, they cannot be used without the encryption key.

Please note that the transmission of credentials should also be secured, for example by using HTTPS. This is not shown in the code but is an important part of securing the credentials.

Also, consider using a secure authentication mechanism, such as OAuth or JWT, instead of storing credentials directly. This can provide additional security benefits and is generally recommended for modern applications.

References