Skip to content

Personally Identifiable Information (PII) Leakage

Personally Identifiable Information (PII) Leakage

Description

Personally Identifiable Information (PII) is, according to NIST Special Publication 800-122, a collective term for any information that can be used to distinguish or trace an individual's identity, such as name, social security number, date and place of birth, mother's maiden name, or biometric records; and any other information that is linked or linkable to an individual, such as medical, educational, financial, and employment information.

In the context of mobile security, PII leakage occurs when plain text PII information is logged to application logs or a world-readable file making it accessible to all applications on the user device.

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

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

        // Assuming you have EditText fields for username and password in your layout
        // with ids 'usernameEditText' and 'passwordEditText' respectively

        loginButton.setOnClickListener {
            val username = usernameEditText.text.toString()
            val password = passwordEditText.text.toString()

            // Log the user credentials
            Log.i("UserCredentials", "Username: $username, Password: $password")

            // Perform login logic here
            performLogin(username, password)

            // Clear the EditText fields after login
            usernameEditText.text.clear()
            passwordEditText.text.clear()
        }
    }
}
import UIKit
import os.log

class ViewController: UIViewController {

    @IBOutlet weak var usernameTextField: UITextField!
    @IBOutlet weak var passwordTextField: UITextField!

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

    @IBAction func loginButtonTapped(_ sender: UIButton) {
        guard let username = usernameTextField.text, !username.isEmpty,
              let password = passwordTextField.text, !password.isEmpty else {
            // Handle empty username or password
            return
        }

        // Log user credentials
        os_log_info("Username: %@, Password: %@", log: .default, type: .info, username, password)

        // Perform login logic here
        performLogin(username, password)

        // Clear text fields after login
        usernameTextField.text = ""
        passwordTextField.text = ""
    }
}
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:logger/logger.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Login Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: LoginPage(),
    );
  }
}

class LoginPage extends StatelessWidget {
  final TextEditingController _usernameController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();

  final logger = Logger(
    printer: PrettyPrinter(),
    output: FileOutput('login_log.txt'),
  );

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Login Page'),
      ),
      body: Padding(
        padding: EdgeInsets.all(20.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            TextField(
              controller: _usernameController,
              decoration: InputDecoration(
                labelText: 'Username',
              ),
            ),
            SizedBox(height: 10.0),
            TextField(
              controller: _passwordController,
              decoration: InputDecoration(
                labelText: 'Password',
              ),
              obscureText: true,
            ),
            SizedBox(height: 20.0),
            ElevatedButton(
              onPressed: () {
                _login(context);
              },
              child: Text('Login'),
            ),
          ],
        ),
      ),
    );
  }

  void _login(BuildContext context) {
    final username = _usernameController.text;
    final password = _passwordController.text;

    // Log user credentials as information
    logger.i('Username: $username, Password: $password');

    // Perform login logic here
    performLogin(username, password)

    // Clear text fields after login
    _usernameController.clear();
    _passwordController.clear();

    // Optionally, you can navigate to another screen or perform other actions after successful login
  }
}

Recommendation

  • Securely delete PII when there is no longer a business need for its retention on the device
  • Do not cache sensitive data
  • Minimize the frequency of asking for user credentials.
  • Minimize the use of APIs that access sensitive or personal user data
  • Consider a logical way to hash the user data
  • Some jurisdictions may require you to provide a privacy policy for accessing personal information.
  • If saving PII information locally is necessary, consider encrypting it before.
  • If logging PII information is necessary, set the logging level to debug so that PII doesn't in production application logs.
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

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

        // Assuming you have EditText fields for username and password in your layout
        // with ids 'usernameEditText' and 'passwordEditText' respectively

        loginButton.setOnClickListener {
            val username = usernameEditText.text.toString()
            val password = passwordEditText.text.toString()

            // Log the user credentials
            Log.d("UserCredentials", "Username: $username, Password: $password")

            // Perform login logic here
            performLogin(username, password)

            // Clear the EditText fields after login
            usernameEditText.text.clear()
            passwordEditText.text.clear()
        }
    }
}
import UIKit
import os.log

class ViewController: UIViewController {

    @IBOutlet weak var usernameTextField: UITextField!
    @IBOutlet weak var passwordTextField: UITextField!

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

    @IBAction func loginButtonTapped(_ sender: UIButton) {
        guard let username = usernameTextField.text, !username.isEmpty,
              let password = passwordTextField.text, !password.isEmpty else {
            // Handle empty username or password
            return
        }

        // Log user credentials
        os_log_debug("Username: %@, Password: %@", log: .default, type: .info, username, password)

        // Perform login logic here
        performLogin(username, password)

        // Clear text fields after login
        usernameTextField.text = ""
        passwordTextField.text = ""
    }
}
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:logger/logger.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Login Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: LoginPage(),
    );
  }
}

class LoginPage extends StatelessWidget {
  final TextEditingController _usernameController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();

  final logger = Logger(
    printer: PrettyPrinter(),
    output: FileOutput('login_log.txt'),
  );

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Login Page'),
      ),
      body: Padding(
        padding: EdgeInsets.all(20.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            TextField(
              controller: _usernameController,
              decoration: InputDecoration(
                labelText: 'Username',
              ),
            ),
            SizedBox(height: 10.0),
            TextField(
              controller: _passwordController,
              decoration: InputDecoration(
                labelText: 'Password',
              ),
              obscureText: true,
            ),
            SizedBox(height: 20.0),
            ElevatedButton(
              onPressed: () {
                _login(context);
              },
              child: Text('Login'),
            ),
          ],
        ),
      ),
    );
  }

  void _login(BuildContext context) {
    final username = _usernameController.text;
    final password = _passwordController.text;

    // Log user credentials as information
    logger.d('Username: $username, Password: $password');

    // Perform login logic here
    performLogin(username, password)

    // Clear text fields after login
    _usernameController.clear();
    _passwordController.clear();

    // Optionally, you can navigate to another screen or perform other actions after successful login
  }
}

Standards

  • OWASP_MASVS_L1:
    • MSTG_ARCH_12
  • OWASP_MASVS_L2:
    • 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