> For the complete documentation index, see [llms.txt](https://docs.payments.thalescloud.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.payments.thalescloud.io/nfc-wallet-sdk-android/security-and-privacy/security-guidance.md).

# Security guidance

## Overview

Use this security guidance when building and releasing an Android **digital wallet application** that integrates the NFC Wallet SDK.

This guidance is a set of security guidelines you must apply before release.

## General security guidelines

### Use the latest NFC Wallet SDK release

Use the latest NFC Wallet SDK release. It includes the latest security updates and fixes.

### Use the Release build of the NFC Wallet SDK

Before publishing to Google Play Store configure the digital wallet application to use the `Release` build.

{% hint style="warning" %}
The `Dev` SDK variant is not allowed in Production Environment.
{% endhint %}

### Strip debug symbols

Do not release with debug symbols. This practice increases the complexity of reverse engineering efforts and prevents the easy identification of sensitive variables, structures, and logic.

### Prevent sensitive data leaks

Clear sensitive data from the UI before the application enters the background.

Encrypt or wipe data until the application returns to the foreground.

Avoid logging sensitive information.

### Use code obfuscation

Use obfuscation to increase the cost of reverse engineering.

### Secure network communication

Use HTTPS for all network calls to the digital wallet backend.

Avoid self-signed certificates.

If you implement certificate pinning, follow these guidelines:

* Match the hostname against the leaf certificate.
* Validate the full certificate chain against the system trust store.
* Reject expired certificates.
* Pin the SHA-256 hash of the root CA or leaf certificate.

If you send confidential data containing personally identifiable information (PII), add application-level encryption and authentication when needed.

### Add RASP protection

Use a commercial Runtime Application Self Protection ([RASP](https://en.wikipedia.org/wiki/Runtime_application_self-protection)) solution.

Detect and respond to:

* Root or jailbreak.
* Debugging.
* Hooking.
* App tampering.
* Emulator execution.

### Logging

Avoid writing sensitive data to device logs.

Use build flags to exclude debug logs from Production Environment builds.

On Android, logs are a shared resource that are accessible with the `READ_LOGS` permission, and inappropriate logging of user sensitive information can lead to unintended data leaks to other application.

### Adopt secure coding practices

Apply secure coding practices throughout development. For exemple you should:

* perform input validation.
* proper management of memory.
* use secure C functions.
* avoide usage of immutable containers for storing sensitive data.

For a baseline checklist, see OWASP [Secure Coding Practices](https://owasp.org/www-project-secure-coding-practices-quick-reference-guide).

These practices can be enforced using static code analysis tools such as PMD or HP Fortify.

### Perform audits and penetration testing

Perform architecture and code audits, plus penetration testing, to identify vulnerabilities and assessing the overall security posture of the application.

### Evaluate the resilience of application security

Check the OWASP MASVS (Mobile Application Security Verification Standard) on [OWASP MASVS](https://github.com/OWASP/owasp-masvs). This is the security requirements baseline for mobile application.

It is highly recommended to use the OWASP MSTG [checklist](https://github.com/OWASP/owasp-mastg/releases/latest) to evaluate the security stature of your application.

## Android developer security guidelines

Use Android security guidance for detailed, defense-in-depth recommendations before release.

Review these topics:

* [Application-level protection](#application-level-protection)
* [Data protection](#data-protection)
* [Authentication](#authentication)
* [Cryptography guidelines](#cryptography-guidelines)
* [Application hardening](#application-hardening)
* [Secure coding](#secure-coding)

{% hint style="info" %}
Use Android’s baseline security checklist as an additional reference to this guidance: [Android security checklist](https://developer.android.com/training/articles/security-tips).
{% endhint %}

### Application-level protection

#### Verify the installer of your application

Verify your digital wallet application's installer package name at runtime.

Only trust installs from Google Play, which uses `com.android.vending`.

To prevent side-channel distribution or unauthorized installations from third-party sources.

#### Enforce security updates (force application update)

Ensure a forced application update in case of security fixes.

* Block access to the service when the installed version is below the minimum allowed version.

#### Store resources in internal storage

Keep your **digital wallet application** and its resources in internal storage. This reduces the risk of a man-in-the-disk (MITD) attack. In MITD attacks, an attacker may modify or manipulate files stored on external storage.

Application should not allow itself to be moved to external storage using the `android:installLocation` manifest attribute.

#### Support SDK-supported OS versions

Run your **digital wallet application** only on OS versions supported by the NFC Wallet SDK. This reduces functional issues and security gaps on older devices. It also improves the **end user** experience.

#### Require a device lock screen

Require the device to have a screen lock. Use a PIN, pattern, or password. Block sensitive flows if no screen lock is set.

```java
KeyguardManager keyguardManager =
        (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);

boolean isDeviceSecure = keyguardManager != null && keyguardManager.isDeviceSecure();

if (!isDeviceSecure) {
    // Block the flow.
    // Prompt the end user to enable a screen lock in Android Settings.
}
```

#### Prevent excessive permissions

Declare only the Android permissions required for your **digital wallet application**.

Unneeded permissions expand the attack surface and can expose privileged data.

#### Restrict exported components

Android applications are built from components:

* Activities
* Services
* Broadcast receivers
* Content providers

Consider:

* Inter-application communication as risky.
* Every exported component as a public entry point into your **digital wallet application,** thereby increasing its exposure to risks and attacks.

We recommend to design your application

* with only a main activity made publicly accessible.
* All other components should explicitly have the attribute `export=false`.

For components to be public, consider protecting them with custom permissions.

#### Disable debugging in release builds

Ensure the `release` build of your **digital wallet application** is not debuggable.

You must:

* Set `android:debuggable="false"` on the `<application>` element in `AndroidManifest.xml`.
* And ensure your final APK is not debuggable.

To verify your final APK:

1. Run:

   ```bash
   aapt dump xmltree <myApplication.apk> AndroidManifest.xml
   ```
2. In the output, locate the `<application>` element. Confirm `android:debuggable` is set to `0x0`.

Automate this verification as part of your CI pipeline.

#### Evaluate app links and deep links

Deep links and app links can increase the attack surface of the application. They can introduce risks such as link hijacking and unintended exposure of sensitive functionality. Behavior varies by Android version:

* Before Android 12 (API level 31), if the application includes any non-verifiable links, the system may not verify all Android App Links for that application.
* Starting from Android 12 (API level 31), the application benefits from a reduced attack surface. Unless the target application is approved for the specific domain in the web intent, the web intent resolves to the end user’s default browser application.

Enumerate all deep links. Verify correct website association.

Test every operation exposed through deep links and app links.

Always validate all input data. Treat all inputs as untrustworthy. Validation ensures the application processes only the data it expects.

#### Prevent screenshots and app previews

Set `FLAG_SECURE` on any activity that displays sensitive data. This prevents sensitive data leak through screenshots in the foreground.

Add the flag in `Activity.onCreate()` before rendering the UI:

```java
@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
}
```

Also clear sensitive information in your activities in `onPause()` method.

#### Proper app signing

Sign your release APK with:

* APK Signature Scheme v1 and v2 for broad Android compatibility.
* APK Signature Scheme v3 when targeting Android 9 (API level 28) and later.

{% hint style="info" %}
Keep the APK signing key under your control. Do not share it.
{% endhint %}

Verify signatures with `apksigner` from Android SDK Build Tools:

```bash
$ apksigner verify --verbose Desktop/example.apk
Verified using v1 scheme (JAR signing): true
Verified using v2 scheme (APK Signature Scheme v2): true Verified using v3 scheme (APK Signature Scheme v3): true Number of signers: 1
```

#### Prevent backup of application data

Disable Android backup and restore for your **digital wallet application**.

Set `android:allowBackup="false"` on the `<application>` element in `AndroidManifest.xml`.

```xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application
        android:allowBackup="false">
    </application>
</manifest>
```

By default, `android:allowBackup` is `true`. This allows the OS to back up and restore application data. This can have security implications.

The backup feature can also let an end user copy application data when USB debugging is enabled.

Once exported, the data can be inspected outside the app sandbox.

#### Limit accessibility on sensitive screens

Android accessibility services can read UI content and trigger actions. This is essential for users with disabilities. It can also be abused by malware to capture sensitive data.

Decide, per screen, whether accessibility services should access sensitive content. Use the techniques below to reduce data leakage through accessibility events.

{% hint style="warning" %}
Blocking accessibility can prevent some **end users** from using your **digital wallet application**. Apply these controls only to truly sensitive screens.
{% endhint %}

**Detect enabled accessibility services**

Check whether any accessibility service is enabled. If needed, limit specific flows when services are enabled.

**Allowlist accessibility services**

Use the Android APIs to list enabled services. Maintain an allowlist or blocklist based on your risk policy. If a disallowed service is enabled, warn the **end user** or block the operation.

**Block accessibility for a view**

You can disable accessibility for a view subtree. This prevents accessibility events from the view and its children.

```java
private void disableAccessibilityEvents(View view) {
    ViewCompat.setImportantForAccessibility(
        view,
        ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
    );
}
```

**Prevent sensitive text from being exposed in accessibility events**

By default, Android may briefly show the last typed character before masking it. This can expose partial input (for example, `***1`) to accessibility services. If this is unacceptable for your threat model, mask characters immediately.

{% code expandable="true" %}

```java
private fun hideLastDigit() {
    transformationMethod = SecureTransformationMethod()
}

class SecureTransformationMethod : PasswordTransformationMethod() {
    override fun getTransformation(source: CharSequence?, view: View?): CharSequence {
        if (source == null) return SecureCharSequence("")
        return SecureCharSequence(source)
    }

    class SecureCharSequence(private val charSequence: CharSequence) : CharSequence {
        override val length: Int
            get() = charSequence.length

        override fun get(index: Int): Char {
            return 'x'
        }

        override fun subSequence(startIndex: Int, endIndex: Int): CharSequence {
            return SecureCharSequence(charSequence.subSequence(startIndex, endIndex))
        }
    }
}
```

{% endcode %}

#### Prevent overlay attacks

Android overlays let one application render UI on top of another. This can enable phishing and data theft. It is a common technique in overlay attacks.

Example phishing scenario: An attacker draws a full-screen overlay on top of your **digital wallet application**. The overlay impersonates a login or PIN screen. This increases the chance of stealing end user credentials.

Protect sensitive screens and inputs. Examples include login, PIN entry, and provisioning.

**Android 12 (API level 31) and later**

Call `setHideOverlayWindows(true)` on sensitive views. This blocks non-system overlays for those views.

**Android 2.3 (API level 9) to Android 11 (API level 30)**

Use touch filtering on sensitive views. This helps detect touches obscured by overlays.

Use one or more of these options:

* Enable `setFilterTouchesWhenObscured(true)` on sensitive views.
* Override `onFilterTouchEventForSecurity()` to reject obscured touch events.
* Check touch events in `onTouch()` and reject obscured events.

{% hint style="warning" %}
Touch filtering does not cover every overlay technique. Some overlays can avoid forwarding touch events. Treat this as defense-in-depth, not a complete solution.
{% endhint %}

For more details, see [Protecting against Android Overlay Attacks](https://www.guardsquare.com/blog/protecting-against-android-overlay-attacks-guardsquare).

#### Use a proprietary keyboard

Avoid third-party keyboards for sensitive inputs. Third-party keyboards can capture what an **end user** types.

Use a proprietary keyboard that is available only in your **digital wallet application**. Use it for PINs, passcodes, passwords, and personally identifiable information (PII).

If you cannot implement a proprietary keyboard, use a dedicated PIN pad for passcode entry. Randomize the key layout per session. This reduces shoulder surfing risk. It can also reduce the impact of some accessibility malware.

### Data protection

#### Protect data in transit

Use TLS 1.2 or TLS 1.3 for all network traffic between your **digital wallet application** and your **issuer backend**.

Configure your **issuer backend** to use strong cipher suites.

In addition:

* Implement **certificate pinning** in your **digital wallet application**.

  On Android 7.0 (API level 24) and later, use [Network security configuration](https://developer.android.com/training/articles/security-config) to pin the domains your application calls.
* Add **application-level encryption and authentication** on top of TLS to protect sensitive payloads (for example, personally identifiable information (PII)) between your **digital wallet application** and your **issuer backend**.

#### Protect stored data

Protect sensitive data stored on the device, even inside the application sandbox.

Assume a compromised device can expose local storage to malware.

It's recommended to encrypt and integrity-protect sensitive data at rest, using device-bound keys, and must require end-user authentication before access.

To encrypt all sensitive data at rest, application can use

* AndroidX Security Crypto `EncryptedSharedPreferences` for key-value data.
* AndroidX Security Crypto `EncryptedFile` for files.

For details, see Android guidance on [data storage](https://developer.android.com/topic/security/data).

### Authentication

#### Support biometric authentication

The **digital wallet application** must support biometric authentication for end-user authentication.

Provide a device credentials (keyguard) fallback when biometrics are unavailable.

Use Android Keystore with `BiometricPrompt` crypto objects when possible.

This binds keys to the device and detects biometric enrollment changes.

#### Enforce multi-factor authentication

Enforce multi-factor authentication (MFA) for sensitive operations in your **digital wallet application**.

MFA adds protection by requiring more than one authentication factor before access.

This reduces the risk of unauthorized access if one factor is compromised.

### Cryptography guidelines

#### Keep Google Play security provider up to date

Use the [Google Play services security provider](https://developer.android.com/training/articles/security-gms-provider) to receive cryptography and TLS fixes on devices that do not receive timely OS updates.

The NFC Wallet SDK does not install, update, or prompt for this provider. Your **digital wallet application** is responsible for ensuring the Google Play services security provider is installed and up to date on the **end user’s** device.

#### Use secure random

Use `java.security.SecureRandom` for all security-sensitive randomness (generate any sensitive cryptographic keys or for any random data generation).

On Android 10 (API level 29) and later, prefer `SecureRandom.getInstanceStrong()` when you require the strongest available source of randomness.

### Application hardening

#### Detect rooted devices

Detect a compromised device environment (for example, rooting frameworks and `su` binaries) before you initialize the NFC Wallet SDK and before you perform any sensitive operation.

See OWASP MSTG guidance on [Android Anti-Reversing Defenses](https://github.com/OWASP/mastg/blob/master/Document/0x05j-Testing-Resiliency-Against-Reverse-Engineering.md).

#### Detect hooking attempts

Hooking injects code into your **digital wallet application** at runtime. Attackers use it to intercept sensitive data (for example, cryptographic keys or PII), bypass security controls, or change application logic.

See OWASP MASVS: [Android Anti-Reversing Defenses](https://mas.owasp.org/MASTG/0x05j-Testing-Resiliency-Against-Reverse-Engineering/) / *Runtime Integrity Verification***.**

#### Detect debugger attachment

On compromised devices, an attacker can attach a debugger to a `Release` build of your **digital wallet application**. This enables step-by-step inspection of Java/Kotlin code and native libraries, and can expose sensitive logic and data.

Detect debugger attachment in both Java/Kotlin and native code, especially before you run sensitive flows. For more information.

See OWASP MASVS: [Android Anti-Reversing Defenses](https://mas.owasp.org/MASTG/0x05j-Testing-Resiliency-Against-Reverse-Engineering/) / *Anti-Debugging*.

#### Detect emulator

Emulators are a non-trusted execution environment. They make dynamic analysis and instrumentation easier for attackers.

Detect emulator execution as early as possible. Do it at application startup, and before you initialize the NFC Wallet SDK.

See OWASP MASVS: [Android Anti-Reversing Defenses](https://mas.owasp.org/MASTG/0x05j-Testing-Resiliency-Against-Reverse-Engineering/) / *Emulator Detection.*

#### Detect application tampering

Detect tampering by verifying the **digital wallet application** signing certificate hash at runtime.

This check helps detect repackaging attacks where an attacker modifies the binary or resources, then re-signs the APK. Attackers cannot reproduce your signing certificate.

Obfuscate the expected certificate hash to make it harder to locate and patch.

For background, see [Implement Anti-tamper Techniques](https://github.com/nowsecure/secure-mobile-development/blob/master/en/coding-practices/anti-tamper-techniques.md).

Optionally, send the signing certificate hash to your **backend**. Verify it server-side before honoring requests from the **digital wallet application**.

#### Obfuscate application

Obfuscate your **digital wallet application** and its components. This increases the cost of reverse engineering. It also makes it harder to locate sensitive logic and data.

Even if the NFC Wallet SDK is already obfuscated with DexGuard, you must obfuscate the Thales NFC Wallet SDK public APIs:

* Ensure the ProGuard/R8 rules provided with the SDK packages are applied.

  See [NFC Wallet SDK obfuscation](/nfc-wallet-sdk-android/security-and-privacy/nfc-wallet-sdk-obfuscation.md)
* Pay special attention to the package flattening rule:

  ```bash
  -flattenpackagehierarchy util
  ```

Use the package name `util` to keep obfuscation output consistent with the SDK rules.

Commercial obfuscation tools are available. On Android, we recommend *DexGuard*.

See OWASP MASVS: [Android Anti-Reversing Defenses](https://mas.owasp.org/MASTG/0x05j-Testing-Resiliency-Against-Reverse-Engineering/) / *Obfuscation*.

### Secure coding

#### **Wipe sensitive data from memory**

Store sensitive data (for example, cryptographic keys and personally identifiable information (PII)) in byte arrays.

In Java, you cannot reliably wipe immutable objects such as `String` and `StringBuilder`. You also cannot control how many copies are created in memory or how long they remain reachable.

Wipe sensitive data explicitly. Do not rely on the garbage collector.

Use a `finally` block to wipe sensitive buffers, even when you do not have a `catch` block. This reduces the risk of leaks if an exception occurs.

{% code expandable="true" %}

```java
byte[] password = this.getUserPassword();
try {
  // Use the password to login
  this.logUserIn(password);
} finally {
  	// Even if there is no exception catch here, there can be a
  	//RuntimeException that should still trigger this finally block
  	// to execute
  MemoryHelper.clearData(password);
}

//One way to implement a byte array wiping method is to rewrite every element in the arrays in the MemoryHelper
class public static void clearData(byte[] baBuffer) {
  if (baBuffer == null)
    return;
  for(i = 0;  i < baBuffer.length; i++) {
    baBuffer[i] = (byte)0;
  }
}

```

{% endcode %}

#### Follow secure coding standards

Follow secure coding standards from trusted sources such as Apple, Google, and OWASP (Open Web Application Security Project).

If you need Thales internal guidance, contact the Thales Handset Security Community to request access.

Enforce these standards with static code analysis tools such as PMD or Fortify. Add them to your CI pipeline to prevent regressions.

#### Run Android lint checks

Run Android Lint during development and before each release. Fix findings early to reduce security and quality risk.

Android Lint is a static analysis tool. It checks your project for correctness, security, performance, usability, accessibility, and internationalization issues.

Run lint locally and in your CI pipeline:

```bash
./gradlew lint
```

For details, see Android developer website: [Improve your code with lint checks](https://developer.android.com/studio/write/lint).

## Protect assets

This section outlines best practices in app development to protect assets.

### **Activation code**

Use in card tokenization with a limited time life cycle:

* Treat as a short-lived secret. Do not log or store

### FCM registration token

If the digital wallet application manages FCM at the app level:

* Avoid persisting the FCM registration token longer than necessary.

### **Funding card information**

If the digital wallet application collects payment card data:

* Disable risky `EditField` options, such as auto-complete, copy, paste, and so on.
* Use a secure keypad.
* Validate inputs before use.
* Do not store payment card data persistently.
* Before showing the input screen, enforce runtime checks (rooting, hooking, debugging, and tampering detection).
* Ensure confidentiality and integrity of this asset.

Apply the same controls to any other sensitive input sourced outside the app.

### App signing certificate and TLS certificate

* Control access to the app signing certificate.
* Do not disclose it to non-trusted parties.
* Ensure confidentiality and integrity of this asset.

### **QR / DSRP inputs data (Amount)**

When the digital wallet application collects the amount:

* Disable risky `EditField` options, such as auto-complete, copy, paste, and so on.
* Use a secure keypad.

Apply the same controls to any other sensitive input sourced outside the app.

### QR Code (2D barcode)

The app must be implemented to detect and to prevent the capturing of QR code in screenshots or from being viewed on non-secure displays.

### Other sensitive assets

* Obfuscate code and protect sensitive strings shipped in the binary.
* Reassess assets on every release (new features could add new sensitive data).
  * Assess the value and criticality of each asset and apply the required protection.
* Do not persist transient data. Clear sensitive data from memory when no longer needed.
* Always consider the device untrusted. Use RASP to help protect the application binary and third-party libraries at runtime.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.payments.thalescloud.io/nfc-wallet-sdk-android/security-and-privacy/security-guidance.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
