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
}
}
Links
- Practices for Protecting Electronic Restricted Data: A Quick Reference
- CWE-200: Information Exposure
- CWE-359: Exposure of Private Information ("Privacy Violation")
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