Skip to content

Insecure Storage of Application Data

Insecure Storage of Application Data

Description

Insecure storage vulnerability in mobile applications refers to a security flaw where sensitive data, such as user credentials, personal information, or other confidential data, is stored on the device in world readable locations. This can leave the data vulnerable to unauthorized access by other applications on the device or by a malicious actor with physical access to the device.

Insecure storage does not only occur when the application writes to world-readable locations but also when the application loads data such as configuration files from world-writable locations where a malicious actor can alter the configuration files and consequently tamper with the functionality of the application.

import android.os.Bundle
import android.os.Environment
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.io.OutputStreamWriter

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val loginButton: Button = findViewById(R.id.login_button)
        loginButton.setOnClickListener {
            // Dummy authentication process
            val token = authenticate("username", "password") // authentication logic

            // Store token in public storage
            storeTokenInPublicStorage(token)
        }
    }

    private fun storeTokenInPublicStorage(token: String) {
        val filePath = "/sdcard/insecure_app/jwt_config.txt"
        val file = File(filePath)
        try {
            val outputStreamWriter = OutputStreamWriter(FileOutputStream(file))
            outputStreamWriter.write(token)
            outputStreamWriter.close()
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }
}
import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.

        let loginButton = UIButton(type: .system)
        loginButton.setTitle("Login", for: .normal)
        loginButton.addTarget(self, action: #selector(loginButtonTapped), for: .touchUpInside)
        view.addSubview(loginButton)
        loginButton.translatesAutoresizingMaskIntoConstraints = false
        loginButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        loginButton.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
    }

    @objc func loginButtonTapped() {
        // Dummy authentication process
        let token = authenticate(username: "username", password: "password")

        // Store token in public storage
        storeTokenInPublicStorage(token: token)
    }


    private func storeTokenInPublicStorage(token: String) {
        let filePath = "/var/mobile/Media/insecure_app/jwt_config.txt"
        let fileURL = URL(fileURLWithPath: filePath)

        do {
            try token.write(to: fileURL, atomically: true, encoding: .utf8)
            print("Token stored successfully.")
        } catch {
            print("Failed to write token: \(error)")
        }
    }
}
import 'dart:io';
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Insecure Storage'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            // Dummy authentication process
            String token = authenticate("username", "password");

            // Store token in public storage
            storeTokenInPublicStorage(token);
          },
          child: Text('Login'),
        ),
      ),
    );
  }

  void storeTokenInPublicStorage(String token) {
    final directory = Directory('/sdcard/insecure_app/');
    directory.createSync(recursive: true);
    final file = File('${directory.path}/jwt_config.txt');
    try {
      file.writeAsStringSync(token);
      print('Token stored successfully.');
    } catch (e) {
      print('Failed to write token: $e');
    }
  }
}

Recommendation

  • Use Secure Storage: Store sensitive data such as authentication tokens or credentials securely. Use secure storage mechanisms provided by the platform, such as Keychain for iOS and SharedPreferences with encryption for Android.
  • Data Encryption: Encrypt sensitive data at rest using strong encryption algorithms to protect data stored on user device.
  • Avoid Hardcoding Sensitive Information: Instead of hardcoding sensitive information like usernames, passwords, or tokens directly into your code, consider secure storage mechanisms suggested above.
  • Avoid Permissive File Permissions: Ensure that file permissions are set appropriately to restrict access to sensitive files and directories. On Android for example, avoid using MODE_WORLD_READABLE or MODE_WORLD_WRITEABLE when creating files, as they grant broad read or write access to all applications. Always follow the principle of least privilege when setting file permissions and limit access to only what is necessary for the application's functionality.
  • Input Validation: When loading data from public storage locations, always make sure to validate and sanitize it.
import android.content.Context
import android.os.Bundle
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKeys
import java.io.IOException

class MainActivity : AppCompatActivity() {

    private lateinit var encryptedSharedPreferences: SharedPreferences

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Initialize encrypted shared preferences
        initializeEncryptedSharedPreferences()

        val loginButton: Button = findViewById(R.id.login_button)
        loginButton.setOnClickListener {
            // Dummy authentication process
            val token = authenticate("username", "password") // authentication logic

            // Store token securely in encrypted shared preferences
            storeTokenInSharedPreferences(token)
        }
    }

    private fun initializeEncryptedSharedPreferences() {
        try {
            val masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)
            encryptedSharedPreferences = EncryptedSharedPreferences.create(
                "secure_preferences",
                masterKeyAlias,
                applicationContext,
                EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
                EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
            )
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }

    private fun storeTokenInSharedPreferences(token: String) {
        encryptedSharedPreferences.edit().putString("jwt_token", token).apply()
        Toast.makeText(this, "Token stored securely.", Toast.LENGTH_SHORT).show()
    }
}
import UIKit
import Security

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.

        let loginButton = UIButton(type: .system)
        loginButton.setTitle("Login", for: .normal)
        loginButton.addTarget(self, action: #selector(loginButtonTapped), for: .touchUpInside)
        view.addSubview(loginButton)
        loginButton.translatesAutoresizingMaskIntoConstraints = false
        loginButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        loginButton.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
    }

    @objc func loginButtonTapped() {
        // Dummy authentication process
        let token = authenticate(username: "username", password: "password")

        // Store token securely in Keychain
        storeTokenInKeychain(token: token)
    }

    private func storeTokenInKeychain(token: String) {
        let keychainQuery: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrAccount as String: "jwtToken",
            kSecValueData as String: token.data(using: .utf8)!,
            kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly
        ]

        let status = SecItemAdd(keychainQuery as CFDictionary, nil)
        if status == errSecSuccess {
            print("Token stored securely in Keychain.")
        } else {
            print("Failed to store token in Keychain: \(status)")
        }
    }
}
import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  final storage = FlutterSecureStorage();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Secure Storage Example'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () async {
            // Dummy authentication process
            String token = await authenticate("username", "password");

            // Store token securely
            await storeTokenInSecureStorage(token);
          },
          child: Text('Login'),
        ),
      ),
    );
  }

  Future<void> storeTokenInSecureStorage(String token) async {
    await storage.write(key: 'jwtToken', value: token);
    print('Token stored securely.');
  }
}

Standards

  • OWASP_MASVS_L1:
    • MSTG_ARCH_4
    • MSTG_ARCH_12
  • OWASP_MASVS_L2:
    • MSTG_ARCH_4
    • MSTG_ARCH_12
  • GDPR:
    • ART_32
    • ART_25
  • PCI_STANDARDS:
    • REQ_3_2
    • REQ_3_3
    • REQ_3_5
    • REQ_3_6
    • REQ_3_7
    • REQ_4_2
    • REQ_6_2
  • OWASP_MASVS_v2_1:
    • MASVS_STORAGE_1
    • MASVS_STORAGE_2
  • SOC2_CONTROLS:
    • CC_2_1
    • CC_4_1
    • CC_6_1
    • CC_7_1
    • CC_7_2
    • CC_7_4
    • CC_7_5