+Best Practices
---+MASTG-BEST-0001 Use Secure Random Number Generator APIs (Android)
---+MASTG-BEST-0002 Remove Logging Code (Android)
---+MASTG-BEST-0003 Comply with Privacy Regulations and Best Practices (Android)
---+MASTG-BEST-0004 Exclude Sensitive Data from Backups (Android)
---+MASTG-BEST-0005 Use Secure Encryption Modes (Android)
---+MASTG-BEST-0006 Use Up-to-Date APK Signing Schemes (Android)
---+MASTG-BEST-0007 Debuggable Flag Disabled in the AndroidManifest (Android)
---+MASTG-BEST-0008 Debugging Disabled for WebViews (Android)
---+MASTG-BEST-0009 Use Secure Encryption Algorithms (Android)
---+MASTG-BEST-0010 Use Up-to-Date minSdkVersion (Android)
---+MASTG-BEST-0011 Securely Load File Content in a WebView (Android)
---+MASTG-BEST-0012 Disable JavaScript in WebViews (Android)
---+MASTG-BEST-0013 Disable Content Provider Access in WebViews (Android)
---+MASTG-BEST-0014 Preventing Screenshots and Screen Recording (Android)
---+MASTG-BEST-0020 Update the GMS Security Provider (Android)
---+MASTG-BEST-0021 Ensure Proper Error and Exception Handling (Android)
---+MASTG-BEST-0022 Disable Verbose and Debug Logging in Production Builds (iOS)
---+MASTG-BEST-0023 Exclude Sensitive Information from Backups (iOS)
---+MASTG-BEST-0024 Store Data Encrypted in App Sandbox Directory (iOS)
---+MASTG-BEST-0025 Use Secure Random Number Generator APIs (iOS)
---+MASTG-BEST-0028 WebViews Cache Cleanup (Android)
---+MASTG-BEST-0030 Implementing Root Detection (Generic)
---+MASTG-BEST-0031 Enforce Strong Biometrics for Sensitive Operations (Android)
---+MASTG-BEST-0032 Migrate from UIWebView to WKWebView (iOS)
---+MASTG-BEST-0033 Securely Load File Content in a WebView (iOS)
---+MASTG-BEST-0034 Validate WebView Input (iOS)
---+MASTG-BEST-0035 Prefer Origin Scoped Messaging Over Legacy JavaScript Bridges (Android)
---+MASTG-BEST-0036 Use Cryptographic Binding for Biometric Authentication (Android)
---+MASTG-BEST-0037 Invalidate Biometric Keys on Enrollment Changes (Android)
---+MASTG-BEST-0038 Require Explicit User Confirmation for Biometric Authentication (Android)
---+MASTG-BEST-0039 Prevent SQL Injection in ContentProviders (Android)
---+MASTG-BEST-0040 Preventing Overlay Attacks (Android)
---+MASTG-BEST-0041 Hardening Against Runtime Hooking (Android)
---+MASTG-BEST-0042 Use Strong TLS Settings in ATS Configuration (iOS)
---+MASTG-BEST-0043 Enforce Strong TLS Settings When ATS Doesn't Apply (iOS)
---+MASTG-BEST-0044 Mask Sensitive Data in Text Input Fields (iOS)
---+MASTG-BEST-0045 Limit Sensitive Data Exposure Through iOS IPC Channels (iOS)
---+MASTG-BEST-0046 Hardening Against Emulation (Android)
---+MASTG-BEST-0047 Continuous Anti-Debugging Checks (Android)
---+MASTG-BEST-0048 Hardening Against Reverse Engineering Tools (iOS)
---+MASTG-BEST-0049 Restrict and Validate Access to Exported Content Providers (Android)
---+MASTG-BEST-0050 Store Data Encrypted in App Sandbox Directory (Android)
---+MASTG-BEST-0051 Minimize iOS Permissions and Entitlements (iOS)
---+MASTG-BEST-0052 Restrict Access to Android App Components (Android)
---+MASTG-BEST-0053 Hardening Against Virtual Devices (iOS)
---+MASTG-BEST-0054 Validate Input Parameters in Custom URL Scheme Handlers (iOS)
---+MASTG-BEST-0055 Validate Source Application in Custom URL Scheme Handlers (iOS)
---+MASTG-BEST-0056 Use Explicit Intents for Internal IPC (Android)
---+MASTG-BEST-0057 Sanitize Data Coming from External Components (Android)
---+MASTG-BEST-0058 Restrict Native Functionality Exposed Through WebView Bridges (iOS)
---+MASTG-BEST-0059 Render Sensitive UI as Native Views Over the WebView (iOS)
---+MASTG-BEST-0060 Use Native Views for Sensitive Text Entry Over a WebView (iOS)
---+MASTG-BEST-0061 Use WKContentWorld Isolation for DOM Inspection Scripts (iOS)
---+MASTG-BEST-0062 Use WKScriptMessageHandlerWithReply to Return Data to JavaScript (iOS)
---+MASTG-BEST-0063 Use Immutable PendingIntents with Explicit Intents (Android)
---+MASTG-BEST-0064 Use Safe APIs for Object Deserialization (iOS)
---+MASTG-BEST-0065 Implementing Storage Integrity Checks on iOS (iOS)
---+MASTG-BEST-0066 Implementing Storage Integrity Checks on Android (Android)
---+MASTG-BEST-0067 Implementing Source Code Integrity Checks on iOS (iOS)
---+MASTG-BEST-0068 Secure Data Sharing Between App Extensions and Containing Apps (iOS)
---+MASTG-BEST-0069 Keep Sensitive Input on the System Keyboard (iOS)
---+MASTG-BEST-0070 Verify Android App Links with autoVerify and Digital Asset Links (Android)
---+MASTG-BEST-0071 Validate Input Parameters in Deep Link and Custom URL Scheme Handlers (Android)
---+MASTG-BEST-0072 Validate Input Parameters in Universal Link Handlers (iOS)
---+MASTG-BEST-0073 Properly Validate Server Trust in URLSessionDelegate and WKNavigationDelegate (iOS)
---+MASTG-BEST-0074 Implementing Anti-Debugging Checks on iOS (iOS)
|
Best Practices
The best practices of the MASTG against the weaknesses of the MASWE.
1. Apžvalga
| Pavadinimas |
Standartas |
|
MASTG-BEST-0001 Use Secure Random Number Generator APIs (Android)
|
Use a cryptographically secure pseudorandom number generator as provided by the platform or programming language you are using. Java/KotlinUse java.security.SecureRandom, which complies with the statistical random number generator tests specified in FIPS 140-2, Security Requirements for Cryptographic Modules, section 4.9.1 and meets the cryptographic strength requirements described in RFC 4086: Randomness Requirements for Security. It produces non-deterministic output and automatically seeds itself during object initialization using system entropy, so manual seeding is generally unnecessary and can weaken randomness if not done properly. The default (no-argument) constructor of SecureRandom is recommended, as it uses the system-provided seed of appropriate length to ensure high entropy. Providing a seed (hardcoded or otherwise) to the constructor is discouraged in the Android Documentation, because it risks creating deterministic output and undermining security. Although the documentation) says the provided seed normally supplements the existing seed, this behavior may differ if an old security provider is used. To avoid these pitfalls, ensure your app targets a modern Android version with an updated provider or explicitly configures a secure provider such as AndroidOpenSSL (or Conscrypt in newer releases). Other LanguagesConsult the standard library or framework documentation to find the API that exposes the operating system's cryptographically secure pseudorandom number generator. This is usually the safest approach, provided there are no known vulnerabilities in that library's random number generation. For example, see the Flutter/Dart issue as a reminder that some frameworks may have known weaknesses in their PRNG implementations.
|
|
MASTG-BEST-0002 Remove Logging Code (Android)
|
Ideally, a release build shouldn't use any logging functions, making it easier to assess sensitive data exposure. Using ProGuardWhile preparing the production release, you can use tools like MASTG-TOOL-0022 (included in Android Studio). To determine whether all logging functions from the android.util.Log class have been removed, check the ProGuard configuration file (proguard-rules.pro) for the following options (according to this [example of removing logging code](https://www.guardsquare.com/en/products/proguard/manual/examples#logging "ProGuard\'s example of removing logging code") and this article about [enabling ProGuard in an Android Studio project](https://developer.android.com/studio/build/shrink-code#enable "Android Developer - Enable shrinking, obfuscation, and optimization")): -assumenosideeffects class android.util.Log
{
public static boolean isLoggable(java.lang.String, int);
public static int v(...);
public static int i(...);
public static int w(...);
public static int d(...);
public static int e(...);
public static int wtf(...);
}
Note that the example above only ensures that calls to the Log class' methods will be removed. If the string that will be logged is dynamically constructed, the code that constructs the string may remain in the bytecode. For example, the following code issues an implicit StringBuilder to construct the log statement: Example in Java: Log.v("Private key tag", "Private key [byte format]: " + key);
Example in Kotlin: Log.v("Private key tag", "Private key [byte format]: $key")
The compiled bytecode, however, is equivalent to the bytecode of the following log statement, which constructs the string explicitly: Example in Java: Log.v("Private key tag", new StringBuilder("Private key [byte format]: ").append(key.toString()).toString());
Example in Kotlin: Log.v("Private key tag", StringBuilder("Private key [byte format]: ").append(key).toString())
ProGuard guarantees removal of the Log.v method call. Whether the rest of the code (new StringBuilder ...) will be removed depends on the complexity of the code and the [ProGuard version](https://stackoverflow.com/questions/6009078/removing-unused-strings-during-proguard-optimisation "Removing unused strings during ProGuard optimization "). This is a security risk because the (unused) string leaks plain text data into memory, which can be accessed via a debugger or memory dumping. Unfortunately, no silver bullet exists for this issue, but one option would be to implement a custom logging facility that takes simple arguments and constructs the log statements internally. SecureLog.v("Private key [byte format]: ", key);
Then configure ProGuard to strip its calls. Custom LoggingYou can implement a custom logging facility and disable it at once only for the release builds.
|
|
MASTG-BEST-0003 Comply with Privacy Regulations and Best Practices (Android)
|
Recommendations from CWE-359. Phase: RequirementsIdentify and consult all relevant regulations for personal privacy. An organization may be required to comply with certain federal and state regulations, depending on its location, the type of business it conducts, and the nature of any private data it handles. Regulations may include Safe Harbor Privacy Framework [REF-340], Gramm-Leach Bliley Act (GLBA) [REF-341], Health Insurance Portability and Accountability Act (HIPAA) [REF-342], General Data Protection Regulation (GDPR) [REF-1047], California Consumer Privacy Act (CCPA) [REF-1048], and others. Phase: Architecture and DesignCarefully evaluate how secure design may interfere with privacy, and vice versa. Security and privacy concerns often seem to compete with each other. - From a security perspective, all important operations should be recorded so that any anomalous activity can later be identified.
- However, when private data is involved, this practice can in fact create risk. Although there are many ways in which private data can be handled unsafely, a common risk stems from misplaced trust.
Programmers often trust the operating environment in which a program runs, and therefore believe that it is acceptable store private information on the file system, in the registry, or in other locally-controlled resources. However, even if access to certain resources is restricted, this does not guarantee that the individuals who do have access can be trusted. References
|
|
MASTG-BEST-0004 Exclude Sensitive Data from Backups (Android)
|
For the sensitive files found, instruct the system to exclude them from the backup: - If you are using Auto Backup, mark them with the
exclude tag in backup_rules.xml (for Android 11 or lower using android:fullBackupContent) or data_extraction_rules.xml (for Android 12 and higher using android:dataExtractionRules), depending on the target API. Make sure to use both the cloud-backup and device-transfer parameters. - If you are using the key-value approach, set up your BackupAgent accordingly.
Refer to "Security recommendations for backups - Mitigations" for more information.
|
|
MASTG-BEST-0005 Use Secure Encryption Modes (Android)
|
Replace insecure encryption modes with secure block cipher modes such as AES-GCM or AES-CCM which are authenticated encryption modes that provide confidentiality, integrity, and authenticity. We recommend avoiding CBC, which while being more secure than ECB, improper implementation, especially incorrect padding, can lead to vulnerabilities such as padding oracle attacks. For comprehensive guidance on implementing secure encryption modes in Android, refer to the official Android Developers documentation on Cryptography.
|
|
MASTG-BEST-0006 Use Up-to-Date APK Signing Schemes (Android)
|
Ensure that the app is signed with at least the v2 or v3 APK signing scheme, as these provide comprehensive integrity checks and protect the entire APK from tampering. For optimal security and compatibility, consider using v3, which also supports key rotation. Optionally, you can add v4 signing to enable faster incremental updates in Android 11 and above, but v4 alone does not provide security protections and should be used alongside v2 or v3. The signing configuration can be managed through Android Studio or the signingConfigs section in build.gradle or build.gradle.kts. To activate both the v3 and v4 schemes, the following values must be set: // build.gradle
android {
...
signingConfigs {
config {
...
enableV3Signing true
enableV4Signing true
}
}
}
|
|
MASTG-BEST-0007 Debuggable Flag Disabled in the AndroidManifest (Android)
|
Ensure the debuggable flag in the AndroidManifest.xml is set to false for all release builds. Note: Disabling debugging via the debuggable flag is an important first step but does not fully protect the app from advanced attacks. Skilled attackers can enable debugging through various means, such as binary patching (see MASTG-TECH-0038) to allow attachment of a debugger or the use of binary instrumentation tools like MASTG-TOOL-0001 to achieve similar capabilities. For apps requiring a higher level of security, consider implementing anti-debugging techniques as an additional layer of defense. Refer to MASWE-0101 for detailed guidance.
|
|
MASTG-BEST-0008 Debugging Disabled for WebViews (Android)
|
Ensure that WebView debugging is disabled in production builds to prevent attackers from exploiting this feature to eavesdrop, modify, or debug communication within WebViews. - Set
WebView.setWebContentsDebuggingEnabled to false in production, or remove the calls entirely if they are unnecessary. - If WebView debugging is required during development, ensure it is enabled only when the app is in a debuggable state by checking the
ApplicationInfo.FLAG_DEBUGGABLE flag at runtime.
For example: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (0 != (getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE))
{ WebView.setWebContentsDebuggingEnabled(true); }
}
Note: Disabling WebView debugging this way helps protect an app already running on a device. For an attacker to exploit WebView debugging, they must have physical access to the device (e.g., a stolen or test device) or remote access through malware or other malicious means. Additionally, the device must typically be unlocked, and the attacker would need to know the device PIN, password, or biometric authentication to gain full control and connect debugging tools like MASTG-TOOL-0004 or Chrome DevTools. However, disabling WebView debugging does not eliminate all attack vectors. An attacker could: - Patch the app to add calls to these APIs (see MASTG-TECH-0038), then repackage and re-sign it (see MASTG-TECH-0039).
- Use runtime method hooking (see MASTG-TECH-0043) to enable WebView debugging dynamically at runtime.
Disabling WebView debugging serves as one layer of defense to reduce risks but should be combined with other security measures.
|
|
MASTG-BEST-0009 Use Secure Encryption Algorithms (Android)
|
Replace insecure encryption algorithms with secure ones such as AES-256 (preferably in GCM mode) or Chacha20. For comprehensive guidance on implementing secure encryption in Android, refer to the documentation on "Cryptography" and "Broken or risky cryptographic algorithm" on the official Android Developers website.
|
|
MASTG-BEST-0010 Use Up-to-Date minSdkVersion (Android)
|
Ensure that the minSdkVersion in the build.gradle file is set to the latest version of the Android platform that aligns with your app's requirements while maintaining compatibility with your user base. Companies often hesitate to increase minSdkVersion because they want their app to be available on as many devices as possible. Even though Google doesn't enforce a specific minSdkVersion, as they do with the targetSdkVersion, it's crucial to understand the implications of setting a low minSdkVersion, as it directly impacts security, exposes users to vulnerabilities, and prevents the app from leveraging critical security protections. Clarifying the Difference: `targetSdkVersion` vs `minSdkVersion`targetSdkVersion: Defines the highest API level the app is _designed_ to run on. The app _can_ run on lower API levels, but it won't necessarily take advantage of all new security enforcements.minSdkVersion: Defines the lowest API level the app is _allowed_ to run on. This is crucial because many security features are only available on devices running a certain API level or higher. If you set a low minSdkVersion, your app completely misses out on these protections on older devices.
Even if you set a high targetSdkVersion, the app can still run on older devices without the latest security improvements. If you set targetSdkVersion=33 (Android 13) but minSdkVersion=21 (Android 5), the app can still be installed on Android 5 devices, which lack years of critical security updates. Malware on these older devices can exploit missing security features that app-level code alone cannot address, as evidenced by vulnerabilities listed in the Android Security Bulletins. While increasing minSdkVersion may slightly reduce the number of devices your app can run on, it significantly enhances security by ensuring that all users have a baseline level of protection. Common MisconceptionsThere are many misconceptions about the minSdkVersion and targetSdkVersion in Android development. The Android documentation sometimes mentions "targeting" when they actually mean "running on." For example: Opt out of cleartext traffic: The guidance in this section applies only to apps that target Android 8.1 (API level 27) or lower. Starting with Android 9 (API level 28), cleartext support is disabled by default.
The note says the guidance applies to apps targeting API 27 or lower. But in reality, even if an app targets API 28+ but is running on an older Android version (below API 28), cleartext traffic is still allowed unless explicitly disabled. Developers might assume that just increasing targetSdkVersion automatically blocks cleartext, which is incorrect. Notable Android Platform Security Improvements Over Time- Android 4.2 (API level 16) in November 2012 (introduction of SELinux)
- Android 4.3 (API level 18) in July 2013 (SELinux became enabled by default)
- Android 4.4 (API level 19) in October 2013 (several new APIs and ART introduced)
- Android 5.0 (API level 21) in November 2014 (ART used by default and many other features added)
- Android 6.0 (API level 23) in October 2015 (many new features and improvements, including granting; detailed permissions setup at runtime rather than all or nothing during installation)
- Android 7.0 (API level 24-25) in August 2016 (new JIT compiler on ART)
- Android 8.0 (API level 26-27) in August 2017 (a lot of security improvements)
- Android 9 (API level 28) in August 2018 (restriction of background usage of mic or camera, introduction of lockdown mode, default HTTPS for all apps)
- Android 10 (API level 29) in September 2019 (enforces TLS 1.3, access location "only while using the app", device tracking prevention, improve secure external storage)
- [Privacy (overview)](https://developer.android.com/about/versions/10/highlights#privacy_for_users "Android 10 Privacy Overview")
- [Privacy (details 1)](https://developer.android.com/about/versions/10/privacy "Android 10 Privacy Details 1")
- [Privacy (details 2)](https://developer.android.com/about/versions/10/privacy/changes "Android 10 Privacy Details 2")
- [Security (overview)](https://developer.android.com/about/versions/10/highlights#security "Android 10 Security Overview")
- [Security (details)](https://developer.android.com/about/versions/10/behavior-changes-all#security "Android 10 Security Details")
- Android 11 (API level 30) in September 2020 (scoped storage enforcement, Permissions auto-reset, reduced package visibility, APK Signature Scheme v4)
- [Privacy (overview)](https://developer.android.com/about/versions/11/privacy "Android 11 Privacy Overview")
- [Privacy Behavior changes (all apps)](https://developer.android.com/about/versions/11/behavior-changes-all "Android 11 Privacy Behavior changes (all apps)")
- [Security Behavior changes (all apps)](https://developer.android.com/about/versions/11/behavior-changes-all#security "Android 11 Security Behavior changes (all apps)")
- [Privacy Behavior changes (apps targeting version)](https://developer.android.com/about/versions/11/behavior-changes-11#privacy "Android 11 Privacy Behavior changes (apps targeting version)")
- [Security Behavior changes (apps targeting version)](https://developer.android.com/about/versions/11/behavior-changes-11#security "Android 11 Security Behavior changes (apps targeting version)")
- Android 12 (API level 31-32) in August 2021 (Material You, Web intent resolution, Privacy Dashboard)
- [Security and privacy](https://developer.android.com/about/versions/12/features#security-privacy "Android 12 Security and privacy")
- [Behavior changes (all apps)](https://developer.android.com/about/versions/12/behavior-changes-all#security-privacy "Android 12 Behavior changes (all apps)")
- [Behavior changes (apps targeting version)](https://developer.android.com/about/versions/12/behavior-changes-12#security-privacy "Android 12 Behavior changes (apps targeting version)")
- Android 13 (API level 33) in 2022 (Safer exporting of context-registered receivers, new photo picker)
- [Security and privacy](https://developer.android.com/about/versions/13/features#privacy-security "Android 13 Security and privacy")
- [Privacy Behavior changes (all apps)](https://developer.android.com/about/versions/13/behavior-changes-all#privacy "Android 13 Privacy Behavior changes (all apps)")
- [Security Behavior changes (all apps)](https://developer.android.com/about/versions/13/behavior-changes-all#security "Android 13 Security Behavior changes (all apps)")
- [Privacy Behavior changes (apps targeting version)](https://developer.android.com/about/versions/13/behavior-changes-13#privacy "Android 13 Privacy Behavior changes (apps targeting version)")
- [Security Behavior changes (apps targeting version)](https://developer.android.com/about/versions/13/behavior-changes-13#security "Android 13 Security Behavior changes (apps targeting version)")
- Android 14 (API level 34) in 2023:
- [Summary of changes](https://developer.android.com/about/versions/14/summary "Android 14 Summary of changes")
- [Security Behavior changes (all apps)](https://developer.android.com/about/versions/14/behavior-changes-all#security "Android 14 Security Behavior changes (all apps)")
- [Security Behavior changes (apps targeting version)](https://developer.android.com/about/versions/14/behavior-changes-14#security "Android 14 Security Behavior changes (apps targeting version)")
- Android 15 (API level 35) in 2024:
- [Summary of changes](https://developer.android.com/about/versions/15/summary "Android 15 Summary of changes")
- [Security Behavior changes (all apps)](https://developer.android.com/about/versions/15/behavior-changes-all#security "Android 15 Security Behavior changes (all apps)")
- [Security Behavior changes (apps targeting version)](https://developer.android.com/about/versions/15/behavior-changes-15#security "Android 15 Security Behavior changes (apps targeting version)")
- Android 16 (API level 36) in 2025 (:material-flask: BETA):
- [Summary of changes](https://developer.android.com/about/versions/16/summary "Android 16 Summary of changes")
- [Security Behavior changes (all apps)](https://developer.android.com/about/versions/16/behavior-changes-all#security "Android 16 Security Behavior changes (all apps)")
- [Security Behavior changes (apps targeting version)](https://developer.android.com/about/versions/16/behavior-changes-16#security "Android 16 Security Behavior changes (apps targeting version)")
|
|
MASTG-BEST-0011 Securely Load File Content in a WebView (Android)
|
The recommended approach to load file content to a WebView securely is to use WebViewClient with WebViewAssetLoader to load assets from the app's assets or resources directory using https:// URLs instead of insecure file:// URLs. This ensures the content is loaded in a secure, same-origin environment and avoids exposing local files to potential cross-origin attacks. If you must allow the WebView to load local files using the file:// scheme, consider the following: - For apps with a
minSdkVersion that has secure defaults for WebView file access methods, ensure that these methods are not used and the default values are preserved. Alternatively, explicitly set them to false to guarantee the WebView does not allow local file access: setAllowFileAccess(false)setAllowFileAccessFromFileURLs(false)setAllowUniversalAccessFromFileURLs(false)- For apps with a
minSdkVersion that does not have secure defaults for these methods (e.g., older API levels), ensure that the above methods are explicitly set to false in your WebView configuration.
For more details, refer to the official Android documentation on loading local content securely, especially the section on "Things to avoid".
|
|
MASTG-BEST-0012 Disable JavaScript in WebViews (Android)
|
Enabling JavaScript is not a vulnerability by itself. In real apps it is often required for legitimate functionality, such as rendering modern web applications, interactive account portals, support centers, payment or login flows, or hybrid app content built with web technologies. Frameworks such as Ionic and Capacitor are built around a WebView that runs JavaScript application code, and react-native-webview exists specifically to render web content in a native view. Android's guidance associates unsafe use of JavaScript enabled WebViews with cross-app scripting. JavaScript does increase the attack surface of a WebView, but severe cases typically happen when it is combined with one or more of the following conditions: loading untrusted or weakly validated content, exposing JavaScript bridges, allowing permissive file or content access, or using unsafe URL loading. Keep JavaScript Disabled in WebViews When Not RequiredJavaScript is disabled by default in WebViews. If JavaScript is not required, do not enable it in the first place or explicitly disable it in WebViews with setJavaScriptEnabled(false). - Keep JavaScript disabled for WebViews that only display static or minimally interactive content. Good candidates include static help pages, legal text, release notes, or other controlled content that does not need client-side scripting.
- Only enable JavaScript when the WebView is intentionally used to run trusted web application logic. Good candidates include hybrid app screens, complex internal web apps, single-page applications, and web-based user experiences that depend on JavaScript to render or function.
Use Alternatives to WebViews for External Content When FeasibleIf you only need to open external web content, consider using Custom Tabs instead of embedding a WebView. If you are shipping a web app you control, Trusted Web Activities may also be appropriate. These options move rendering into the browser context rather than your app's WebView, which can reduce app specific WebView risk. They do not remove the need to secure the web content itself. Custom Tabs are especially appropriate for authentication and other browser-based flows because Android recommends them for sign-in, noting that the host app cannot inspect the content. Trusted Web Activities also prevent the host app from having direct access to web content or web state such as cookies and localStorage. Hardening WebViews When JavaScript Is RequiredIf JavaScript is required, apply WebView specific hardening measures, covered in related MASTG best practices, to mitigate the increased attack surface. This includes, but is not limited to: - Only load expected and allowlisted origins.
- Validate scheme and host before calling
loadUrl, shouldOverrideUrlLoading, or similar APIs. - Disable file and content access unless they are strictly needed (MASTG-BEST-0011 and MASTG-BEST-0013).
- Avoid exposing JavaScript bridges to untrusted content (MASTG-BEST-0035).
- Enable Safe Browsing where supported by the WebView implementation, for example by calling
WebSettings.setSafeBrowsingEnabled(true)) (available since Android 8.0, API level 26).
|
|
MASTG-BEST-0013 Disable Content Provider Access in WebViews (Android)
|
Unlike other file content access methods from WebSettings, the setAllowContentAccess method always defaults to true. Therefore, whenever access to content providers isn't explicitly needed, ensure that the setAllowContentAccess method is set to false to prevent WebViews from accessing content providers. Why is this important?Enabling content access in a WebView is not a vulnerability per se; it increases the number of ways an attacker could chain vulnerabilities. For example, if combined with an XSS or other injection vulnerability (or if the WebView is used to display untrusted remote content), it can allow an attacker to read sensitive data that they can send back to a remote server. Although there are many "safeguards" (such as CORS restrictions and the fact that a non-exported provider won't serve data to any external caller), the app's own content providers would be accessible even if they were not exported; they may have access to the app's private storage, both in internal and external storage. Also in some cases even other apps' files in shared/external storage, depending on the app permissions (e.g. READ_MEDIA_IMAGES, etc.).
|
|
MASTG-BEST-0014 Preventing Screenshots and Screen Recording (Android)
|
Ensure the app hides sensitive content, such as card numbers and passcodes, from screenshots, screen recording, nonsecure displays, task switcher thumbnails, and remote screen sharing. Malware may capture screen output and extract confidential information. Protect on screen keyboards or custom keypad views as they may leak keystrokes from passcode fields. Screenshots can be saved in locations accessible to other apps or a local attacker. Setting FLAG_SECURE on the window prevents screenshots (or appear black), blocks screen recording, and hides content on nonsecure displays and in the system task switcher. <div style="display:flex; flex-wrap:wrap; gap:16px; align-items:flex-start; margin:16px 0;"> <figure style="flex:1 1 220px; margin:0; text-align:center;"> <img src="Images/Chapters/0x05d/task-switcher-without-flag-secure.png" width="200" alt="Task switcher without FLAG_SECURE"> <figcaption>Without FLAG_SECURE</figcaption> </figure> <figure style="flex:1 1 220px; margin:0; text-align:center;"> <img src="Images/Chapters/0x05d/task-switcher-with-flag-secure.png" width="200" alt="Task switcher with FLAG_SECURE"> <figcaption>With FLAG_SECURE</figcaption> </figure> </div> You can follow the official documentation to implement FLAG_SECURE in your app, see "Secure sensitive activities".
|
|
MASTG-BEST-0020 Update the GMS Security Provider (Android)
|
Android devices vary widely in OS version and update frequency. Relying solely on platform-level security can leave apps exposed to outdated SSL/TLS implementations and known vulnerabilities. The GMS Security Provider (delivered via Google Play Services) addresses this by updating critical cryptographic components—such as OpenSSL and TrustManager, independently of the Android OS. This helps ensure secure network communication, even on older or unpatched devices. It is strongly recommended to check and update the Security Provider early during app startup, ideally before making any secure network connections. Follow the Android Developer Documentation on [how to update the Security Provider to protect against SSL exploits](https://developer.android.com/privacy-and-security/security-gms-provider "Updating Your Security Provider to Protect Against SSL Exploits"). If your app needs to support devices both with and without Google Play Services (such as Huawei devices, Amazon tablets, or AOSP-based ROMs), implement runtime checks to detect Play Services availability. - On GMS-enabled devices, use the Security Provider to keep cryptographic libraries up to date.
- On non-GMS devices, consider bundling a secure TLS library like Conscrypt to ensure consistent and strong network security across your entire device fleet.
|
|
MASTG-BEST-0021 Ensure Proper Error and Exception Handling (Android)
|
Secure exception and error handling in Android is about preventing the leakage of sensitive information, managing failures gracefully, and ensuring that errors do not compromise security. User-facing error messages should remain generic, while controlled logging is reserved for developers. The OWASP DevGuide reinforces these principles with a focus on not disclosing internal details to end users, not disclosing sensitive user data to developers, and ensuring secure failure modes that do not weaken authentication or authorization. - Avoid leaking sensitive information: Error messages shown to users should be generic and not reveal internal details. Logs should be sanitized to remove sensitive data and restricted to authorized personnel. The official Log Info Disclosure guidance warns against including sensitive data or stack traces in production logs and recommends sanitization and reduced verbosity.
- Fail securely: Exceptions must not weaken security controls. Any failure in security checks should result in a deny outcome, blocking the action rather than allowing weaker assumptions or insecure fallbacks. Security mechanisms should default to denying access until explicitly granted, since fail-open paths are a common attack vector.
- Validate strictly and abort on errors: Unexpected formats or values should be treated as errors. Do not continue in a partially verified state. For example, if a network call succeeds at the transport layer but fails validation at the application layer, processing must stop. If the validation fails, do not try to sanitize the data to make the validation succeed.
See these resources for more details:
|
|
MASTG-BEST-0022 Disable Verbose and Debug Logging in Production Builds (iOS)
|
When logging information, it's crucial to protect sensitive values and avoid exposing unnecessary implementation details. Keep Production Logs MinimalUse logging only for operational events that are necessary for support and monitoring. Production logs should be limited to high-level, non-sensitive events that are useful for monitoring and support. Good examples include a generic authentication failure, a network timeout, or an unexpected state transition. In particular, avoid logging: - full request or response headers and bodies.
- authentication tokens, cookies, session identifiers, or API keys.
- usernames, email addresses, or other personal data unless strictly necessary and appropriately protected.
- full error objects, diagnostic context, attached metadata, nested causes, or stack traces.
- backend hostnames, staging endpoints, feature flags, or internal module and class names.
- certificate validation behavior, SSL pinning status, retry logic, or other network security details.
Use Logging APIs with Privacy ControlsWhen logging is required, prefer the APIs that use Apple's Unified Logging system: Logger in Swift or os_log in Objective-C. Avoid ad hoc logging through print, NSLog, or third-party SDKs that do not support structured logging and privacy controls. Privacy ModifiersApple's Unified Logging system provides privacy modifiers that let you control how data appears in logs. .private redacts the value in persistent logs while still allowing debugging workflows..private(mask:) can preserve limited correlation, for example by hashing a value without exposing the original..sensitive behaves like .private, but remains redacted even when private data logging is enabled..public (not recommended) explicitly marks a value as safe to display in logs. Use this only for non-sensitive operational information.
Privacy modifiers help protect individual values, but they do not make verbose logging safe by themselves. The principle of minimal logging still applies. Log LevelsApple's Unified Logging system supports multiple log levels so you can categorize messages by importance and severity. debug for detailed debugging information.info for general operational messages.error for failures the app can recover from.fault for serious failures that require immediate attention.
Use these levels carefully. Higher quality logging is not about emitting more detail, it is about emitting only the detail that is appropriate for the environment. In production, avoid using log levels as a reason to include sensitive values or internal implementation details. Use Macros or Build Flags to Disable Verbose Logging in ProductionTo reduce risk, verbose diagnostics should be compiled out of release builds whenever possible. This is especially important for print, NSLog, and ad hoc debugging statements. 1. Swift#if DEBUG
print("Hello world")
#endif
2. Objective-C#ifdef DEBUG
# define NSLog(...) NSLog(__VA_ARGS__)
#else
# define NSLog(...)
#endif
Then set the DEBUG flag in Apple Clang - Preprocessing > Preprocessor Macros for development builds only.
|
|
MASTG-BEST-0023 Exclude Sensitive Information from Backups (iOS)
|
iOS does not provide a guaranteed mechanism to exclude files from backups. Setting NSURLIsExcludedFromBackupKey instructs the system not to include a file in backups, but it does not ensure exclusion. To reduce data exposure, apply the following techniques: Bind Data to the Current DeviceStore sensitive data in the Keychain and mark it with kSecAttrAccessibleWhenUnlockedThisDeviceOnly or kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly to keep secrets restricted to the current device. When implementing this, create a new Keychain entry and set the kSecAttrAccessible attribute to one of the ThisDeviceOnly values when inserting the item. Handling Larger FilesFor larger files, store them encrypted within the app container and keep the decryption key in the Keychain using a ThisDeviceOnly accessibility class. When you need to use the files, decrypt them only into RAM or into non‑backed‑up locations such as /Library/Caches or /tmp. Note that these locations are _purgeable_, and the system may delete their contents at any time; avoid treating them as durable storage. Be prepared to re‑decrypt the files on demand if they are cleared. Bind Data to the User via a Server-Managed KeyIf binding to the device is insufficient, you can instead bind data to a user by storing the decryption key on your server and releasing it only after successful authentication. Do not persist this key on the device; keep it only in RAM and decrypt files as described above.
|
|
MASTG-BEST-0024 Store Data Encrypted in App Sandbox Directory (iOS)
|
Choose the right location for storing the app's and the user's data to the app sandbox: use Documents directory to store user-generated content and Library directory for app's internal data. An app can be configured to make Documents directory accessible to the user in the Files app by setting UIFileSharingEnabled and LSSupportsOpeningDocumentsInPlace. Therefore, storing databases, config files, purchase state in this directory is highly dangerous because: - a user can tamper with internal app files
- an attacker with a physical access to the device can copy content of
Documents directory - other apps can access
Documents directory of other apps with a document picker interface
Note: Storing data in the correct directory doesn't mean it's secure. For L2 profile apps, it's recommended to encrypt the files before storing them, and put the encryption key into the Keychain.
|
|
MASTG-BEST-0025 Use Secure Random Number Generator APIs (iOS)
|
Use secure random number generator APIs that are backed by the operating system _cryptographically secure pseudorandom number generator (CSPRNG)_. Do not build your own _pseudorandom number generator (PRNG)_. Swift / Objective-C- Security Framework (preferred): Use the
SecRandomCopyBytes) API from the Security framework, which produces cryptographically secure random bytes backed by the system CSPRNG. - CommonCrypto: You _could_ use
CCRandomCopyBytes or CCRandomGenerateBytes (not documented on the Apple Developers website), which are also backed by the system CSPRNG. However, prefer SecRandomCopyBytes which is a wrapper around these functions. - Swift Standard Library: You can use the Swift Standard Library
.random APIs which are backed by SystemRandomNumberGenerator. However, note that their random number generator can be customized, so ensure you use the default SystemRandomNumberGenerator (e.g., by not specifying a custom generator) or a secure alternative (ensure it is cryptographically secure). - CryptoKit: CryptoKit doesn't expose a direct random byte generator, but it provides secure random nonces and keys through its cryptographic operations, which are backed by the system CSPRNG. For example, you can use
SymmetricKey for keys and AES.GCM.Nonce for nonces without needing to manage raw random bytes directly.
See MASTG-KNOW-0070 for code examples of these APIs. Other LanguagesConsult the standard library or framework to locate the API that exposes the operating system CSPRNG. This is usually the safest path, provided the library itself has no known weaknesses. For cross-platform or hybrid apps on iOS rely on frameworks that forward calls to the underlying system CSPRNG. For example:
|
|
MASTG-BEST-0028 WebViews Cache Cleanup (Android)
|
Android WebViews cache data when the server responds with specific Cache-Control headers that instruct the browser to cache the content. If a WebView processes sensitive data, you should ensure that no residual information remains on the device (disk and/or RAM) once the WebView is no longer required. Prefer server-side cache prevention by using headers such as Cache-Control: no-cache in API responses that contain sensitive data to instruct the webview not to cache. If server-side control is not possible or as a supplementary control, explicitly set WebSettings.setCacheMode()) with WebSettings.LOAD_NO_CACHE or clear the WebView cache with WebView.clearCache(includeDiskFiles = true)) after WebView use (such as on WebView Activity's onDestroy lifecycle call) to reduce this risk. However, this method comes with two disadvantages: - The first disadvantage is indiscriminately deleting all cached data, including non-sensitive items that actually benefit from the cache, such as bigger files like images.
- The second disadvantage is the lack of a guarantee that the clear method will always be called, particularly if the app process is killed abruptly. In this case, evaluation of prior cache clearing and active clearing would be required, such as at the next app start.
MASTG-KNOW-0018 describes the different storage areas used by WebViews.
|
|
MASTG-BEST-0030 Implementing Root Detection (Generic)
|
Root detection is an environment risk signal that helps identify devices with elevated privilege or common rooting artifacts. It is a cost raising measure and it is bypassable, so it should be used only when rooted device risk materially impacts the app. Apply the relevant root detection techniques described in MASTG-KNOW-0027 based on the app's threat model and risk tolerance. Best Practices- Layer defenses: Pair root signals with integrity checks, anti debugging signals, and backend enforcement.
- Distribute checks: Place checks near sensitive operations and session establishment, avoid a single centralized gate.
- Use multiple methods: Combine filesystem artifacts, property checks, process checks, and native level checks.
- Avoid well-known patterns only: Do not rely only on public signature lists or a single library default configuration.
- Use proportional responses: Limit high risk operations first, add step up authentication, avoid full lockout when confidence is low.
- Validate server-side: Use server policy to decide whether to allow transactions, based on risk and user context.
- Rotate and randomize: Vary which checks run per session and per release, rotate indicators to reduce reusable bypass patches.
Caveats and ConsiderationsRoot detection is inherently bypassable through hooking and patching, and by hiding root artifacts. See MASTG-TECH-0144. Root detection can flag legitimate scenarios such as custom ROMs, enterprise test devices, and security research environments. Aggressive blocking can push users to modified app builds, and can increase support costs.
|
|
MASTG-BEST-0031 Enforce Strong Biometrics for Sensitive Operations (Android)
|
For sensitive operations protected by Android biometrics, configure BiometricPrompt to require BIOMETRIC_STRONG rather than allowing weaker biometric classes. Android defines BIOMETRIC_STRONG as authentication using a Class 3 biometric, while BIOMETRIC_WEAK corresponds to Class 2 biometric authentication. When the operation is intended to be biometric only, don't include DEVICE_CREDENTIAL in the allowed authenticators. DEVICE_CREDENTIAL enables fallback to the device screen lock credential (PIN, pattern, or password) instead of requiring a biometric factor. While not inherently a vulnerability, for high-security applications (e.g., finance, government, health) its use reduces the intended security posture and makes authentication more susceptible to shoulder surfing and social engineering.
|
|
MASTG-BEST-0032 Migrate from UIWebView to WKWebView (iOS)
|
Apple deprecated UIWebView in iOS 12 in favor of WKWebView for better security and performance. Migrate your app to WKWebView to benefit from its improved security features, such as out-of-process rendering and enhanced JavaScript control. WKWebView allows you to disable JavaScript entirely, preventing script injection vulnerabilities, and provides better isolation between web content and the app, reducing the risk of memory corruption affecting the main app process. Additionally, WKWebView supports modern web security features like Content Security Policy (CSP), which can further enhance the security of your web content.
|
|
MASTG-BEST-0033 Securely Load File Content in a WebView (iOS)
|
Avoid Enabling `allowFileAccessFromFileURLs` and `allowUniversalAccessFromFileURLs`For WKWebView, allowFileAccessFromFileURLs and allowUniversalAccessFromFileURLs are not part of the public iOS WKWebView API. They are commonly accessed through Key-Value Coding (KVC), but should remain disabled unless there is a specific, well justified need. If you must enable these properties, ensure that: - The WebView only loads trusted content from controlled sources.
- Proper input validation and sanitization are implemented.
- The app does not store sensitive data in locations accessible to the WebView.
These settings apply only to WKWebView. UIWebView historically allowed broader local file access and lacked the modern isolation and control model provided by WKWebView, which is one reason UIWebView was deprecated and replaced. See MASTG-BEST-0032. Load Local Files SecurelyWhen loading local HTML using loadHTMLString(_:baseURL:)/) or load(_:mimeType:characterEncodingName:baseURL:)), set the baseURL deliberately. - For
WKWebView, setting baseURL to nil gives the document an opaque origin. This prevents it from being treated as same origin with local files and helps stop access to other local resources. - If the page needs bundled subresources such as CSS, images, or JavaScript, prefer
loadFileURL(_:allowingReadAccessTo:)) or loadFileRequest(_:allowingReadAccessTo:)) with a narrowly scoped read access URL. - If you do use a
file:// base URL, keep it limited to a controlled resource location such as the app bundle.
Avoid broad file:// base URLs unless they are strictly necessary. Use `loadFileURL` and `loadFileRequest` CarefullyWhen using loadFileURL(_:allowingReadAccessTo:)) or loadFileRequest(_:allowingReadAccessTo:)), ensure that the allowingReadAccessTo parameter grants the minimum required file system scope. // Good: Restrict access to a specific file
let fileURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
.appendingPathComponent("safe.html")
webView.loadFileURL(fileURL, allowingReadAccessTo: fileURL)
// Risky: Grants access to an entire directory
let dirURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
webView.loadFileURL(fileURL, allowingReadAccessTo: dirURL) // Avoid if possible
If directory access is required, ensure that the directory contains only WebView assets and no sensitive app data. Additional ConsiderationsEven when these precautions are followed, WebViews should only load content from trusted sources. If attacker-controlled JavaScript executes in a WebView that can read local files, it may read and exfiltrate sensitive data from the app sandbox. - Disable content JavaScript when the WebView only displays static content, using
WKWebpagePreferences.allowsContentJavaScript = false. - Avoid loading untrusted input into WebViews to prevent HTML or JavaScript injection.
- Keep WebView accessible files separate from app data, secrets, and credentials.
- Prefer loading content from the app bundle or controlled sources instead of broad
file:// paths. - Consider App Bound Domains for WebViews that should only access app controlled domains and use powerful WebKit APIs.
|
|
MASTG-BEST-0034 Validate WebView Input (iOS)
|
Always treat any data passed to a WKWebView as untrusted unless it is fully controlled by the app. This includes URLs loaded through load(_:)), local files loaded through loadFileURL), HTML passed to loadHTMLString), JavaScript passed to evaluateJavaScript), and any data inserted into the rendered page. If the app loads a URL into a WKWebView, the URL should be parsed and validated against a strict allowlist of expected schemes, hosts, paths, and other relevant components. Do not allow attacker-controlled input, such as deep links, custom URL schemes, pasted text, or server-supplied values, to determine arbitrary WebView destinations. For deep links and custom URL schemes, only accept known commands and fixed destinations. Do not forward arbitrary URL parameters directly into WKWebView.load(_:). If untrusted data must be displayed inside web content, avoid HTML and JavaScript injection patterns such as innerHTML or string built evaluateJavaScript calls. Prefer safe text only rendering and context appropriate escaping. If local content is loaded with loadFileURL, keep allowingReadAccessTo as narrow as possible and never combine broad local file access with untrusted HTML or script injection.
|
|
MASTG-BEST-0035 Prefer Origin Scoped Messaging Over Legacy JavaScript Bridges (Android)
|
JavaScript bridges are not inherently unsafe, but they are a high-impact WebView feature and should only be exposed to content you fully trust. The main risk is not the bridge alone, but the combination of a bridge with untrusted or weakly validated content. Avoid the Legacy `addJavascriptInterface` ModelThe legacy addJavascriptInterface mechanism is exposed to every frame in the WebView, including iframes, and does not provide origin-based access control. This makes it unsuitable as a security boundary when the WebView may render untrusted or weakly validated content. Android also notes that one safer way to use addJavascriptInterface() is to target API level 21 or higher), because then JavaScript can only access methods explicitly annotated with @JavascriptInterface, whereas older target levels also exposed public fields of the injected object. Even with that improvement, the mechanism still lacks origin-based access control, so Android recommends newer origin-aware alternatives for modern bridge designs. Prefer `addWebMessageListener` When a Bridge Is RequiredAndroid explicitly documents addWebMessageListener as the recommended modern bridge mechanism. It is described as the most modern and recommended approach, and the mechanism comparison table marks it as Recommended: Yes and Security: Highest (Allowlist-based). Use it when you need communication between web content and native code and can define a narrow allowlist of trusted origins. Configure a strict allowedOriginRules set, register the listener before calling loadUrl(), and validate the sender information in the callback before processing messages. Use `postWebMessage` Only as an AlternativeAndroid documents postWebMessage as an alternative asynchronous messaging mechanism. In the same comparison table it is marked Recommended: No and Security: High (Origin-aware), which is stronger than addJavascriptInterface but not as strong as addWebMessageListener. If this mechanism is used, configure a strict target origin and avoid wildcard targets such as *. Android's security guidance specifically warns that lack of origin control in postWebMessage() and postMessage() can allow attackers to intercept messages or send messages to native handlers. Minimize Exposed Native FunctionalityRegardless of the bridge mechanism, minimize the native functionality exposed to JavaScript: - expose only the specific operations the page needs
- avoid broad utility objects or generic command dispatchers
- do not expose sensitive capabilities unless they are essential
- require simple, well-defined message formats
- reject unexpected inputs and unsupported actions
Scope and LimitationsThis best practice is about bridge design and origin scoping. It should be combined with related controls for JavaScript enablement, trusted origin restrictions, and file access hardening. It does not by itself prevent attacker-controlled JavaScript from executing in a trusted page.
|
|
MASTG-BEST-0036 Use Cryptographic Binding for Biometric Authentication (Android)
|
For sensitive operations protected by biometric authentication, use BiometricPrompt.authenticate()) with a CryptoObject backed by an Android Keystore key configured with setUserAuthenticationRequired(true). This cryptographically binds the authentication result to the key operation, ensuring that the sensitive operation can only proceed after successful biometric verification. Without a CryptoObject, authentication is event-bound and relies solely on the onAuthenticationSucceeded callback. This makes it susceptible to runtime logic manipulation, for example by hooking the callback to return success without actually passing biometric verification. Keystore Key ConfigurationWhen generating the key with KeyGenParameterSpec.Builder, configure: setUserAuthenticationRequired(true)): requires the user to authenticate before the key can be used.setUserAuthenticationParameters(0, type)): a timeout of 0 requires authentication for every individual cryptographic operation. Avoid extended validity durations for sensitive operations, as the key remains usable for the entire validity window even if the device is later accessed by an unauthorized person.
Note setUserAuthenticationValidityDurationSeconds(int)) is deprecated from API level 30 in favor of setUserAuthenticationParameters(int, int).
|
|
MASTG-BEST-0037 Invalidate Biometric Keys on Enrollment Changes (Android)
|
When generating cryptographic keys for biometric authentication, ensure keys are invalidated when new biometrics are enrolled. Either configure setInvalidatedByBiometricEnrollment(true)) explicitly, or rely on the default behavior, which invalidates keys when setUserAuthenticationRequired(true) is set. When setInvalidatedByBiometricEnrollment(false) is used, a key remains valid even after new biometrics are enrolled. An attacker who obtains the device passcode could enroll a new biometric and use it to access existing encrypted data or trigger sensitive operations. By invalidating keys on enrollment changes, only biometrics that were enrolled when the key was created can unlock it, preventing newly enrolled biometrics from accessing previously protected data. Note Key invalidation is immediate and permanent when a new biometric is enrolled. The app must handle KeyPermanentlyInvalidatedException and guide the user to re-authenticate to create a new key.
|
|
MASTG-BEST-0038 Require Explicit User Confirmation for Biometric Authentication (Android)
|
For sensitive operations requiring explicit user authorization (e.g., payments or access to health data), configure setConfirmationRequired(true)) in BiometricPrompt.Builder, or rely on the default behavior, which requires confirmation. When setConfirmationRequired(false) is used, passive biometrics such as face recognition can authenticate the user implicitly as soon as the device detects their biometric data. This means authentication can complete without the user actively acknowledging the operation, which may not be appropriate for high-value actions. The Android documentation notes that explicit confirmation provides assurance that the user intentionally initiated the sensitive operation, particularly when passive biometric modalities are used.
|
|
MASTG-BEST-0039 Prevent SQL Injection in ContentProviders (Android)
|
The ContentProvider enables Android applications to share data with other applications and system components. If a ContentProvider constructs SQL queries using untrusted input from URIs, IPC calls, or Intents without validation or parameterization, it becomes vulnerable to SQL injection. Attackers can take advantage of this vulnerability to bypass access controls and extract sensitive data. Improper handling of URI path segments, query parameters, or selection arguments in ContentProvider queries can lead to arbitrary SQL execution. - Use Parameterized Queries: Instead of building SQL using string concatenation, use
selection and selectionArgs parameters.
For example: val idSegment = uri.getPathSegments()[1]
val selection = "id = ?"
val selectionArgs = arrayOf(idSegment)
val cursor = qb.query(db, projection, selection, selectionArgs, null, null, sortOrder)
- Use Prepared Statements: When performing insert, update, or delete operations, use SQLite prepared statements (for example,
SQLiteStatement or SQLiteDatabase methods that support argument binding) instead of dynamically constructed SQL. Prepared statements ensure that untrusted input is bound as parameters and cannot alter the structure of the SQL query, effectively preventing SQL injection even when input originates from URIs or IPC calls.
Refer to "Protect against malicious input" for more information.
|
|
MASTG-BEST-0040 Preventing Overlay Attacks (Android)
|
Apps should protect sensitive user interactions from overlay attacks by implementing appropriate defensive mechanisms. Overlay attacks (including tapjacking) occur when malicious apps place deceptive UI elements over legitimate app interfaces to trick users into unintended actions. Implement appropriate mechanisms to protect against overlay attacks. The following approaches are listed from most robust to least robust: Prevention MechanismsThese mechanisms prevent overlays from appearing or block touch events when overlays are detected: - Use
HIDE_OVERLAY_WINDOWS permission and setHideOverlayWindows(true) (API level 31+): Declare the HIDE_OVERLAY_WINDOWS permission in the manifest and call setHideOverlayWindows(true)) on the window to hide all non-system overlay windows while the activity is in the foreground. This is the most robust solution as it prevents overlays entirely rather than just filtering touch events.
- Set
android:filterTouchesWhenObscured="true" or call setFilterTouchesWhenObscured(true): Set the layout attribute android:filterTouchesWhenObscured="true" in XML for sensitive views, or call setFilterTouchesWhenObscured(true)) programmatically on sensitive views such as login buttons, payment confirmations, or permission requests. This filters touch events when the view is obscured by another visible window.
- Override
onFilterTouchEventForSecurity: Override the onFilterTouchEventForSecurity) method for more granular control and to implement custom security policies based on your app's specific requirements.
Detection MechanismsThese mechanisms detect when overlays are present but do not automatically prevent them. They allow the app to respond accordingly: - Check motion event flags such as
FLAG_WINDOW_IS_OBSCURED (API level 9+) or FLAG_WINDOW_IS_PARTIALLY_OBSCURED (API level 29+) in touch event handlers to detect obscured windows and respond appropriately. Note that this approach requires custom implementation to decide how to handle detected overlays.
Apply these protections selectively to security-sensitive UI elements where user confirmation is critical, such as: - Login and authentication screens
- Permission request dialogs
- Payment confirmation buttons
- Sensitive data entry fields
- Security settings changes
Caveats and Considerations- Touch filtering is not a complete solution on older Android versions that have system-level vulnerabilities. Apps should target modern API levels when possible.
- Some attacks, particularly those exploiting system-level vulnerabilities (for example, Toast Overlay on Android versions before 8.0), cannot be fully mitigated at the app level.
- Applying touch filtering too broadly may impact legitimate use cases where overlays are expected (for example, system dialogs, accessibility features).
- Users can still be tricked through social engineering even with touch filtering enabled. Apps should combine these protections with user education and clear UI indicators.
- For maximum protection, apps targeting older API levels should consider upgrading their
targetSdkVersion to benefit from platform-level protections introduced in newer Android versions.
|
|
MASTG-BEST-0041 Hardening Against Runtime Hooking (Android)
|
Defending against runtime hooking requires a layered approach that combines several types of security controls: - Preventive controls: Implement root detection (MASTG-KNOW-0027) and device/app attestation (MASTG-KNOW-0120, MASTG-KNOW-0119) as the first line of defense, since most hooking frameworks (e.g., Frida server, Xposed) require rooted devices.
- Detective controls: Scan for tool signatures using artifact-based detection (MASTG-KNOW-0030) and verify the app's code and memory integrity at runtime (MASTG-KNOW-0032) to detect hooking attempts.
- Deterrent controls: Obfuscate detection logic, scatter checks throughout the app, and vary their timing to increase the cost and effort required to bypass protections.
- Responsive controls: Terminate the session, clear sensitive data from memory, or even alert the backend server when a threat is detected.
Because hooking can also occur on non-rooted devices (e.g., by repackaging the app with an embedded frida-gadget, see MASTG-TECH-0026), do not rely solely on preventive controls. Apply the detective, deterrent, and responsive controls described below to protect against hooking regardless of the device's root status. Detective ControlsCombine Artifact-Based and Integrity-Based DetectionImplement both artifact-based detection (MASTG-KNOW-0030) and runtime integrity verification (MASTG-KNOW-0032). Use artifact-based detection to scan for known tool signatures (e.g., Frida server processes, libraries, open ports) and runtime integrity verification to detect the _modifications_ these tools make to the app's code and memory (e.g., GOT hooks, inline trampolines, ART method entry point changes). Do not rely on only one approach, as each has blind spots the other covers. Apply Multiple Detection TechniquesLayer several techniques to maximize detection coverage: - Memory scanning: Scan
/proc/self/maps and process memory for known artifacts (e.g., "LIBFRIDA", frida-agent libraries, Xposed bridge classes). - Integrity checksums: Compute checksums of critical code sections at build time and verify them periodically at runtime to detect patches and inline hooks.
- GOT/PLT verification: Verify that Global Offset Table entries point to addresses within their expected libraries.
- Function prologue inspection: Compare the first bytes of security-critical functions against their expected values to detect trampoline patterns (e.g.,
LDR X16, .+8; BR X16 on ARM64). - ART method verification: Use JNI's
FromReflectedMethod to confirm that Java method entry points fall within legitimate regions (OAT file, interpreter, or JIT code cache). - Network-based checks: Probe for D-Bus responses on open ports to reveal frida-server even when renamed.
Deterrent ControlsImplement Detection in Native CodeConsider writing detection checks in native (C/C++) code rather than Java/Kotlin. Native code is significantly harder to hook and reverse engineer than Java bytecode, which can be easily intercepted via Frida's Java API or Xposed modules. Note
Remember, that if you use JNI to bridge results back to the application layer for any responsive controls, an attacker can tamper the results. Obfuscate Detection LogicApply code obfuscation (MASTG-KNOW-0033) across all detection routines. Scatter checks throughout the application instead of centralizing them in a single function, and vary their timing - such as periodically, randomly, or based on events (see [Repeat Checks Before Sensitive Operations](#repeat-checks-before-sensitive-operations) - to prevent systematic bypassing.) Inline Detection LogicAvoid placing detection code in dedicated, callable functions. A named function has a fixed entry point that hooking frameworks can intercept with a single hook. When detection logic is inlined directly into the surrounding application code, there is no entry point to target — the check becomes an inseparable part of the surrounding control flow. The most reliable approach is to copy the detection logic directly at each call site, leaving no function entry point to target. When compiler assistance is preferred, use __attribute__((always_inline)) in native C/C++ or private inline in Kotlin for a compile-time inlining guarantee. Randomize Check Placement Per ReleaseBeyond scattering checks within a single build, vary which call sites are active and where they appear with each release. Because most app updates leave the overall logic largely unchanged, static analysis of one version can be reused to find and patch checks in the next. Randomizing check placement at build time forces attackers to do fresh analysis for every release, significantly increasing the cost of maintaining automated bypass tools. Use build-time code transformation (such as LLVM passes, custom Gradle tasks, or R8/ProGuard rules) to inject detection calls at different locations, move or remove existing call sites, and change the number of active checks between builds. Combine this with native code implementation and obfuscation for maximum impact. Repeat Checks Before Sensitive OperationsPerform checks multiple times from different locations, especially immediately before critical actions like starting a transfer, unlocking a premium feature, or submitting credentials. Spreading out checks to obscure their purpose can be helpful, but an attacker who patches one instance can still access the critical step. Making all redundant checks pass before a sensitive operation completes ensures that each bypassed instance becomes a potential failure point, significantly increasing the difficulty for an attacker to succeed. Responsive ControlsTrigger the following response actions when hooks are detected: - Terminate the app session immediately.
- Clear sensitive data from memory and/or disk.
- Alert the backend server to flag the compromised session.
Do not allow the app to continue running in a compromised state. Protect the response mechanism itself against hooking by implementing it in native code and obfuscating its control flow.
|
|
MASTG-BEST-0042 Use Strong TLS Settings in ATS Configuration (iOS)
|
App Transport Security (ATS) enforces strong TLS defaults for URLSession connections on iOS 9 and later. Avoid weakening these defaults through ATS exceptions in Info.plist, and ensure any custom TLS configuration in code is equally strong. Avoid Lowering the Minimum TLS VersionNote Since iOS 26, URLSession and the Network framework now enforce a minimum TLS version of 1.2. ATS exceptions configured to allow TLS 1.0 or 1.1 are no longer accepted by the operating system.
Do not set NSExceptionMinimumTLSVersion to TLSv1.0 or TLSv1.1 for any domain. TLS 1.0 and TLS 1.1 are deprecated and have known weaknesses. Apple requires a justification for this exception when submitting to the App Store and recommends fixing the server rather than weakening the client configuration. If a third-party service requires TLS 1.0 or 1.1, contact the service provider to request an upgrade. Treat any such exception as temporary and remove it once the server is updated. When configuring URLSessionConfiguration in code, do not set tlsMinimumSupportedProtocolVersion or the deprecated tlsMinimumSupportedProtocol to values corresponding to TLS 1.0 or 1.1. Prefer leaving the default, which inherits ATS minimum requirements. Avoid Disabling Forward SecrecyDo not set NSExceptionRequiresForwardSecrecy to false. ATS enforces Perfect Forward Secrecy (PFS) by default using ECDHE cipher suites. Disabling PFS means that past sessions can be decrypted if the server's private key is later compromised. Prefer the URL Loading System for HTTPS RequestsAlways prefer URLSession or other high-level Foundation APIs for HTTPS requests so that ATS protections apply automatically. Avoid using Network.framework, CFNetwork, or BSD sockets for application-level HTTPS unless you explicitly configure and enforce strong TLS settings in code, because ATS does not protect those connection paths. See MASTG-BEST-0043 for guidance on those APIs. Apply Narrow Exceptions When RequiredWhen an ATS exception is unavoidable, apply it as narrowly as possible: - Target only the specific domain that requires the exception.
- Avoid setting
NSIncludesSubdomains = true unless all subdomains require the exception. - Do not set
NSAllowsArbitraryLoads to true. This disables ATS for all connections to domains not listed in NSExceptionDomains, removing TLS version enforcement, certificate validation, and forward secrecy requirements for those domains. Per-domain exceptions in NSExceptionDomains still apply to their listed domains, but all unlisted domains have no ATS protection. - Provide a justification in the app's App Store submission as required by Apple.
|
|
MASTG-BEST-0043 Enforce Strong TLS Settings When ATS Doesn't Apply (iOS)
|
App Transport Security (ATS) only protects connections made through the URL Loading System (URLSession and related Foundation APIs). When your app uses Network.framework, CFNetwork, BSD sockets, or a bundled third-party TLS library, ATS doesn't apply and you're responsible for configuring strong TLS settings explicitly. Apple's documentation states that "ATS doesn't apply to calls your app makes to lower-level networking interfaces like the Network framework or CFNetwork. In these cases, you take responsibility for ensuring the security of the connection." See Preventing Insecure Network Connections. When possible, prefer URLSession and high-level Foundation APIs so that ATS protections apply automatically. See MASTG-BEST-0042. Network.frameworkNote Since iOS 26, URLSession and the Network framework now enforce a minimum TLS version of 1.2.
When using NWConnection with TLS, configure NWProtocolTLS.Options and set the minimum TLS version to at least TLS 1.2 using sec_protocol_options_set_min_tls_protocol_version): let tlsOptions = NWProtocolTLS.Options()
sec_protocol_options_set_min_tls_protocol_version(
tlsOptions.securityProtocolOptions,
.TLSv12
)
Embedded Third-Party TLS LibrariesSome apps bundle networking stacks such as OpenSSL, BoringSSL, mbedTLS, or curl that manage TLS independently from any Apple API. Configure them to require TLS 1.2 or later, use strong cipher suites, and enable full certificate chain validation. No OS-level mechanism will catch a misconfiguration in a bundled library. Regularly audit and update bundled libraries to incorporate security fixes.
|
|
MASTG-BEST-0044 Mask Sensitive Data in Text Input Fields (iOS)
|
For any text input field that handles sensitive information such as passwords, PINs, or OTPs, ensure that the entered text is visually masked to prevent bystanders or screen capture tools from exposing it. UIKitSet isSecureTextEntry to true on any UITextField that captures sensitive data. This replaces typed characters with bullet characters (•) and prevents the text from appearing in plain text. let passwordField = UITextField()
passwordField.isSecureTextEntry = true
SwiftUIUse SecureField instead of TextField for any input that handles passwords, PINs, or OTPs. SecureField automatically masks its content as the user types. SecureField("Password", text: $password)
Note Do not use a plain TextField for sensitive input, even if you intend to style it to look like a masked field at the application layer, because this does not provide the same level of protection as the system-provided secure text entry mechanisms.
|
|
MASTG-BEST-0045 Limit Sensitive Data Exposure Through iOS IPC Channels (iOS)
|
- Platform: iOS
- Knowledge: MASTG-KNOW-0083, MASTG-KNOW-0079, MASTG-KNOW-0080, MASTG-KNOW-0081, MASTG-KNOW-0082, MASTG-KNOW-0122, MASTG-KNOW-0123, MASTG-KNOW-0124, MASTG-KNOW-0125, MASTG-KNOW-0126, MASTG-KNOW-0127, MASTG-KNOW-0128, MASTG-KNOW-0129, MASTG-KNOW-0130, MASTG-KNOW-0131, MASTG-KNOW-0104
When your app exchanges data across iOS IPC channels, share the minimum amount of data for the shortest time possible. Design these flows so that intercepted payloads are low value and short lived. Follow the principle of least privilege: grant each IPC channel and shared container only the minimum permissions required for its intended purpose, and validate all inbound data as untrusted input. For guidance on channel behavior, see MASTG-KNOW-0078. Restrict Pasteboard UsageAvoid placing sensitive values in UIPasteboard.general unless there is a strict product requirement. If you must use the pasteboard, set restrictive options with setItems(_:options:)), such as UIPasteboard.OptionsKey.localOnly and UIPasteboard.OptionsKey.expirationDate. Prefer Short-Lived Exchange DataFor URL-based interfaces, such as custom URL schemes and Universal Links, avoid embedding long-lived secrets, tokens, credentials, or personal data in URLs. Use one-time or short-lived references and have the receiving side redeem them through an authenticated channel. Apply the same pattern to Handoff, Siri Shortcuts, App Intents, shared files, and document exchange flows. Pass references, identifiers, or scoped URLs instead of full sensitive payloads whenever possible. Validate All IPC InputTreat data received through IPC channels as untrusted input, even when it comes from a system-mediated flow. Validate URLs, pasteboard contents, shared files, document imports, App Intent parameters, Siri Shortcut parameters, NSUserActivity.userInfo, and files read from App Group containers before use. Reject unexpected schemes, hosts, file types, identifiers, entity references, and parameter combinations. Enforce authorization checks in the receiving handler, not only in the normal app UI. Constrain Shared Container DataWhen using App Groups, store only data that must be shared with extensions or companion apps. Protect files with the Data Protection API, and remove shared artifacts as soon as they are no longer needed, for example after the receiving process confirms consumption or after a short server-defined timeout. Any app or extension in the App Group can potentially read or modify shared data, so avoid storing secrets, session tokens, or high-value personal data unless strictly necessary. Limit Shared Keychain AccessWhen using Keychain access groups, create dedicated shared groups for specific use cases instead of sharing broadly across all apps from the same team. Store only items that must be shared, and protect them with appropriate kSecAttrAccessible* and access control settings. Review all apps and extensions that declare the same access group, because each one becomes part of the trust boundary for the shared keychain items. Avoid storing overly sensitive data such as hashed passwords in the keychain, even in non-shared access groups. On jailbroken devices, the keychain of any process can be read directly, so items stored there are not protected in that threat model. Coordinate and Audit Shared File AccessWhen multiple processes access shared files, use MASTG-KNOW-0127 to keep access patterns explicit and predictable. This is especially important for App Group containers, external documents, open in place flows, and files that may be modified by another app, extension, or File Provider. Review shared file locations during code review and testing. Check file permissions, Data Protection classes, cleanup behavior, locking, and whether stale files can expose sensitive data after the intended exchange is complete. Protect Document Exchange FlowsFor document picker, document interaction, share sheet, and open in place flows, treat received files as untrusted input. Validate file type, size, structure, and content before parsing. Avoid assuming that the declared Uniform Type Identifier accurately reflects the file contents. When opening external documents, access only the files selected by the user and release security scoped access as soon as it is no longer needed. Minimize App Intent, Siri Shortcut, and Handoff DataFor App Intents, Siri Shortcuts, and Handoff, avoid placing secrets or unnecessary personal data in intent parameters, shortcut configuration, donated interactions, entity metadata, dialogs, summaries, Spotlight metadata, or NSUserActivity.userInfo. Require confirmation or authentication for sensitive, destructive, financial, privacy-impacting, or irreversible actions. App Intent and shortcut handlers should perform the same authorization checks as the corresponding in-app flow. Secure Network-Based IPCFor Bonjour, local sockets, HTTP, and backend-mediated communication, do not rely on local network presence as a trust signal. Authenticate peers, encrypt traffic where appropriate, and validate all messages. Bonjour provides service discovery, not transport security. The connection established after discovery still requires normal authentication, authorization, transport protection, and input validation. Avoid Unsupported Low-Level IPCXPC, Mach ports, and CFMessagePort are not designed for general-purpose communication between unrelated third-party iOS apps. The iOS sandbox prevents direct use of these mechanisms between apps from different developers. Prefer Apple-supported system-mediated APIs, App Groups, Keychain access groups, document exchange, App Intents, Siri Shortcuts, Handoff, or network protocols where appropriate. If low-level IPC appears in app extensions, platform-specific extension mechanisms, enterprise builds, or security research contexts, review the exposed interface, accepted messages, entitlements, sandbox profile, input validation, and authorization checks.
|
|
MASTG-BEST-0046 Hardening Against Emulation (Android)
|
Emulated devices allow target applications to be executed in controlled environments that may use custom system images, modified platform components, or instrumentation that is difficult for the app to detect. This enables advanced reverse-engineering techniques. Defending against emulated devices involves a layered approach that commonly consists of applying several types of security controls: - Detective controls: Scan for common device emulator indicators and properties (MASTG-KNOW-0031) and use the Google Play Integrity API (MASTG-KNOW-0035) to help identify risky devices, emulated environments, modified app binaries, and other untrusted interactions.
- Deterrent controls: Obfuscate this detection logic (MASTG-KNOW-0033), scatter checks throughout the app, and vary their timing to increase the cost and effort required to bypass these checks.
- Hardening against reverse-engineering tools: Implement detection of reverse-engineering tools (MASTG-KNOW-0030), as custom or emulated environments are often combined with such tools.
|
|
MASTG-BEST-0047 Continuous Anti-Debugging Checks (Android)
|
Implement frequent anti-debugging checks during sensitive execution paths instead of relying on a one-time check at startup. A one-time check is easy to bypass because an attacker can attach a debugger after initialization and continue analysis without triggering the initial detection logic. Re-checking debugger state at runtime raises attacker effort and improves resilience. On Android, you can combine Java and native checks depending on your threat model. For example, use Debug.isDebuggerConnected()) in Java flows and complement it with native checks in sensitive JNI paths. Furthermore, tight continuous polling loops can be resource heavy. A good balance is to implement checkpoint-based checks before sensitive actions (for example, key use, payment approval, privileged API calls, or secrets access) and short periodic checks only while sensitive flows are active. This model reduces overhead while still making post-start debugger attachment harder. Treat anti-debugging as a defense-in-depth control, not as a standalone guarantee. Advanced attackers can still bypass checks through patching, instrumentation, or hooks.
|
|
MASTG-BEST-0048 Hardening Against Reverse Engineering Tools (iOS)
|
Defending against reverse engineering tools on iOS requires a layered approach that combines several types of security controls: - Detective controls: Scan for known reverse engineering tool artifacts (MASTG-KNOW-0087), such as checking loaded dynamic libraries via
_dyld_image_count/_dyld_get_image_name for names containing "frida", "gadget", "cynject", or other tool-specific strings. This technique is effective against Frida Gadget (embedded mode) and tools loaded through dyld, but on official builds frida-server injects its agent using a custom Mach-O loader that bypasses dyld, so it does not detect frida-server in injected mode. Additionally, probe TCP port 27042 for a D-Bus authentication response to reveal a running frida-server. - Deterrent controls: Obfuscate detection logic (MASTG-KNOW-0089), scatter checks throughout the app, and vary their timing to increase the cost and effort required to bypass these checks. Avoid centralizing detection in a single function, as a fixed entry point can be patched or hooked.
- Responsive controls: Terminate the app immediately, clear sensitive data from memory, or alert the backend server when a tool is detected.
Detective ControlsInspect Loaded Dynamic LibrariesUse _dyld_image_count() and _dyld_get_image_name() to iterate over all loaded dynamic libraries and check for names associated with reverse engineering tools. Known artifact names to look for include FridaGadget, frida-agent, cynject, and similar strings. _dyld_image_count only returns images tracked by dyld, so this technique is effective against Frida Gadget (embedded mode) and tools loaded through dyld such as via DYLD_INSERT_LIBRARIES. However, on official builds frida-server injects its agent using a custom Mach-O loader that bypasses dyld, and its injector prioritizes the mapper over dyld, rendering this technique ineffective for the most common jailbroken scenario. An attacker can also bypass a name-based check by renaming the library, so combine this with the D-Bus port detection technique discussed below for better coverage. Apply Multiple Detection TechniquesLayer several techniques to maximize detection coverage: - Library name scanning: Iterate loaded dylibs using
_dyld_image_count/_dyld_get_image_name for known artifact names (see [Inspect Loaded Dynamic Libraries](#inspect-loaded-dynamic-libraries) above for its coverage and limitations). - TCP port probing: Check whether port 27042 is open and responds to a D-Bus AUTH message, which reveals a default frida-server configuration.
- Named pipe detection: Scan for named pipes used by frida-server for inter-process communication.
See MASTG-KNOW-0087 for a detailed discussion of each technique and its bypass difficulty. Deterrent ControlsImplement Detection in Native CodeWrite detection checks in C rather than Swift or Objective-C. Native code is significantly harder to hook than Swift/Objective-C, which can be intercepted via Frida's ObjC or Swift APIs. When bridging results back to the application layer via native calls, be aware that the bridging call itself can be hooked. Obfuscate Detection LogicApply code obfuscation (MASTG-KNOW-0089) across detection routines. Scatter checks throughout the application instead of centralizing them, and vary their timing — for example, periodically, on random events, or immediately before sensitive operations — to prevent systematic bypassing. Inline Detection LogicAvoid placing detection code in dedicated, named functions. A named function has a fixed entry point that can be patched with a single hook. Inlining the detection logic directly at each call site removes that fixed target. Responsive ControlsWhen a reverse engineering tool is detected: - Terminate the app session immediately.
- Clear sensitive data from memory.
- Alert the backend server to flag the compromised session.
Do not allow the app to continue running in a compromised state. Protect the response mechanism itself by implementing it in native code and obfuscating its control flow.
|
|
MASTG-BEST-0049 Restrict and Validate Access to Exported Content Providers (Android)
|
Content Providers are not inherently unsafe, but database-backed and file-backed providers can expose sensitive data if they are exported, have weak permissions, or grant access through overly broad URI scopes. To reduce data exposure and follow the least-privilege security principle, apply the below techniques: Keep Content Providers Non-ExportedIf a provider is only used within the app, set android:exported="false" explicitly. Although providers are not exported by default since API level 17, explicit configuration is easier to audit and safer for mixed/legacy codebases. <provider
android:name="org.owasp.mastestapp.MastgTest$AppointmentProvider"
android:authorities="org.owasp.mastestapp.appointments"
android:exported="false" />
As a result, apps on the device are not able to query the provider at all. Permissions on Exported Content ProvidersIf the Content Provider must be exported, access should be restricted using one or more of the following <provider> manifest attributes: android:readPermission: Required permission to query or read data from the provider.android:writePermission: Required permission to insert, update, or delete data in the provider.android:permission: A single permission that covers both read and write access. It is overridden by readPermission or writePermission when those are set.
<provider
android:name="org.owasp.mastestapp.MastgTest$AppointmentProvider"
android:authorities="org.owasp.mastestapp.appointments"
android:exported="true"
android:readPermission="org.owasp.mastestapp.permission.READ_APPOINTMENTS" />
Setting one or more of these manifest attributes makes Android check whether the caller has actually been granted the required permission. Declaring <uses-permission> in the client manifest only requests the permission; whether the request is granted depends on the permission's protectionLevel (covered in the next section). <uses-permission android:name="org.owasp.mastestapp.permission.READ_APPOINTMENTS" />
Protection Levels on Exported Content ProvidersA protectionLevel defines the conditions under which Android will grant a declared <permission> to a requesting app. For example, automatically at install time (normal), only after explicit user approval (dangerous), or exclusively to apps signed with the same developer certificate (signature). The following example, declared by the provider app, enforces that only client apps signed with the same developer certificate are allowed to use the content provider. <permission
android:name="org.owasp.mastestapp.permission.READ_APPOINTMENTS"
android:protectionLevel="signature" />
A custom permission without an explicit protectionLevel defaults to normal. This means any app can request and typically receive it automatically, so it is a weak security boundary. The readPermission/writePermission attributes on the provider are the enforcement point, but the declared permission's protectionLevel determines how strong that enforcement is. Share Files Securely with FileProviderFor sharing files with other apps, Android recommends using FileProvider with a non-exported provider, narrow path mappings, and temporary URI grants. FileProvider enforces path scoping based on a declarative configuration and refuses to serve files outside the declared subtrees, including paths that attempt to escape via ...
Declare a Narrow Scope in file_paths.xmlDeclare only the specific subdirectories that should be shareable. Each path element maps to a directory on the device, as documented in the FileProvider reference: <files-path>: a subpath of Context.getFilesDir()<cache-path>: a subpath of Context.getCacheDir()<external-files-path>: a subpath of the app-specific external files directory<external-cache-path>: a subpath of the app-specific external cache directory<external-path>: a subpath of Environment.getExternalStorageDirectory()
Pick the narrowest path that satisfies the use case. For example, if only PDF reports under filesDir/reports/ should be shareable: <!-- res/xml/file_paths.xml -->
<paths>
<files-path name="reports" path="reports/" />
</paths>
Files outside the declared subtrees (such as filesDir/session_token.txt) cannot be addressed through the provider. Configure the FileProvider in the ManifestKeep the provider non-exported and enable per-URI grants. The android:grantUriPermissions="true" attribute allows other apps to be granted temporary access through FLAG_GRANT_READ_URI_PERMISSION or FLAG_GRANT_WRITE_URI_PERMISSION: <provider
android:name="androidx.core.content.FileProvider"
android:authorities="org.owasp.mastestapp.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
Share Files via URIs with Temporary GrantsUse FileProvider.getUriForFile()) to obtain a content:// URI for a file inside one of the declared subtrees, then attach FLAG_GRANT_READ_URI_PERMISSION to the Intent that hands the URI to the receiving app. Requests for files outside the declared paths throw IllegalArgumentException. The grant is scoped to that single URI, the receiving app does not need to declare any manifest permission, and the grant expires when the receiving task ends. val report = File(context.filesDir, "reports/lab_result_3829.pdf")
val uri = FileProvider.getUriForFile(
context,
"org.owasp.mastestapp.fileprovider",
report
)
val intent = Intent(Intent.ACTION_VIEW).apply {
setDataAndType(uri, "application/pdf")
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
startActivity(intent)
For sensitive workflows, minimize each grant to the required access mode (read vs. write), and revoke explicit grants with Context.revokeUriPermission()) once they are no longer needed. Avoid <root-path> and path="." declarations <root-path> maps the provider root to / and can make any app-accessible file reachable through the provider if the app grants such a URI. It does not bypass Android/Linux file permissions, but it is still too broad for secure sharing. Setting path="." on any path element exposes the entire corresponding directory, including files added later such as authentication tokens, databases, or logs. Always declare a specific subdirectory.
|
|
MASTG-BEST-0050 Store Data Encrypted in App Sandbox Directory (Android)
|
Store sensitive data in SharedPreferences only after encrypting it. Standard SharedPreferences stores values in XML files inside the app's private data directory, so values such as credentials, authentication tokens, private keys, or personally identifiable information (PII) should not be stored in cleartext. For apps that use SharedPreferences, use EncryptedSharedPreferences or an equivalent mechanism that encrypts preference keys and values before they are written to disk. An equivalent mechanism should use authenticated encryption, protect encryption keys with the Android Keystore or another appropriate key management system, and avoid custom cryptography. Note EncryptedSharedPreferences is part of the Jetpack Security Crypto library. All APIs in that library were deprecated in version 1.1.0, and Android states that there will be no subsequent releases. It may still be a practical mitigation for existing apps that must keep using SharedPreferences, but it should not be treated as a long term storage strategy. Monitor Android's cryptography and DataStore guidance, and plan a migration to a supported encryption approach when available.
Android recommends DataStore as a modern replacement for SharedPreferences, but DataStore does not encrypt data by default. If you migrate sensitive data to DataStore, use an appropriate encryption layer before writing the data. AndroidX introduced the androidx.datastore:datastore-tink artifact for DataStore encryption support in version 1.3.0-alpha07. This provides encryption using the Tink library and AeadSerializer, which wraps an existing DataStore serializer and performs authenticated encryption and decryption. See the DataStore release notes for more information and an example of use.
|
|
MASTG-BEST-0051 Minimize iOS Permissions and Entitlements (iOS)
|
Request only the iOS permissions and app capabilities that the app actually needs, and prefer the narrowest Apple-supported access model for each feature. This reduces unnecessary exposure of personal data and limits the blast radius if the app, an extension, or a shared container is later abused. Review Info.plist purpose strings, the signed entitlements, and any provisioning-profile entitlements together before release. A permission prompt or capability should map to a concrete feature that users can understand and justify. Remove unused or speculative entries instead of keeping them "just in case". Prefer Narrower Access PathsWhen Apple provides a user-selected or limited-access API, prefer it over broad library or background access. For example, use PHPickerViewController or PhotosPicker when users only need to choose specific photos, and request full photo library access only when the app genuinely needs it. For location, request when in use access before considering broader background access. For Bluetooth, HealthKit, HomeKit, Siri, or other protected services, enable only the capabilities and usage-description keys that are strictly required for the implemented feature set. Minimize Data-Sharing CapabilitiesTreat entitlements such as App Groups, iCloud containers, and Associated Domains as sensitive design decisions, not default conveniences. They can create new paths for sharing, syncing, or exposing personal data across apps, extensions, websites, or devices. Before enabling one of these capabilities, document the exact data flow it unlocks, the minimum set of targets that need it, and the security controls that protect the data afterward. If the same feature can be implemented without broad shared containers or external associations, prefer the narrower design. Note Newer Apple privacy mechanisms such as privacy manifests and required-reason APIs complement these checks but do not replace purpose strings or entitlements. You still need to minimize and review both.
|
|
MASTG-BEST-0052 Restrict Access to Android App Components (Android)
|
Only export an app component when another app genuinely needs to interact with it. Every exported component is an entry point that other apps on the device may be able to invoke, so keeping components private by default reduces the app's attack surface. Set the exported status explicitlyDeclare android:exported="false" on every manifest-declared component that doesn't need to be accessible to other apps. Don't rely on the default value: it has changed across Android versions and component types, and an <intent-filter> historically makes a component exported unless the attribute is set explicitly. Since Android 12 (API level 31), any activity, service, or broadcast receiver with an intent filter must explicitly declare android:exported. For context-registered receivers, when registering the receiver with a registerReceiver() overload that accepts flags, explicitly pass RECEIVER_NOT_EXPORTED in the flags parameter unless the receiver must accept broadcasts from other apps. Use RECEIVER_EXPORTED only when external broadcasts are required. Setting android:exported="false" (for manifest-declared components) or RECEIVER_NOT_EXPORTED (for context-registered receivers) prevents ordinary apps, including separate apps from the same developer, from accessing the component. Components within the same app, apps sharing the same user ID, and privileged system components can still reach it. If the component is only used internally, remove its <intent-filter> and use an explicit intent to reach it. Use android:exported="true" with an appropriate permission, usually signature, when a separate trusted app must access the component. Require an effective permission when appropriateIf a component must be exported but should only be accessible to specific apps, protect it with android:permission and use a permission with a protection level appropriate for the intended callers. A custom permission with signature protection is usually appropriate when access should be limited to apps signed with the same key. Do not treat the presence of android:permission as sufficient by itself: a broadly grantable protection level (normal or dangerous) may still allow untrusted apps to invoke sensitive components. See MASTG-KNOW-0017 for Android permission protection levels and custom permissions. For context-registered receivers, when registering an exported receiver that should only accept broadcasts from specific apps, pass an appropriate permission in the broadcastPermission parameter. This restricts which apps can send broadcasts to the receiver. The permission should resolve to a trusted <permission> declaration with an appropriate protection level, usually signature. For example, define the permission in the manifest of the app that owns the receiver or in another trusted package: <permission
android:name="com.example.app.permission.SEND_INTERNAL_BROADCAST"
android:protectionLevel="signature" />
Then require that permission when registering the receiver: registerReceiver(
myReceiver,
IntentFilter("com.example.app.ACTION_INTERNAL"),
"com.example.app.permission.SEND_INTERNAL_BROADCAST",
null,
Context.RECEIVER_EXPORTED
)
|
|
MASTG-BEST-0053 Hardening Against Virtual Devices (iOS)
|
Virtual devices, such as MASTG-TOOL-0108 and newer research environments, allow target applications to be executed in controlled environments that may use custom system images, modified platform components, missing or simulated hardware capabilities, or instrumentation that is difficult for the app to detect. This enables advanced reverse-engineering techniques. Do not confuse virtual devices with the iOS Simulator or with iPhone and iPad apps running on macOS. The iOS Simulator runs simulator builds, while virtual devices attempt to reproduce an iOS device environment for iOS device binaries. iPhone and iPad apps running on macOS use a separate official Mac App Store distribution path on Macs with Apple silicon. See MASTG-KNOW-0088 and MASTG-KNOW-0136. Defending against virtual devices requires a layered approach. Local checks should be treated as risk signals, not as standalone security decisions, because attackers can hook, patch, or bypass client-side logic. For sensitive functionality, combine client-side indicators with server-side validation and policy decisions. Common controls include: - Virtual device detection: Check for virtual device indicators such as missing hardware capabilities, inconsistent device properties, known virtualization artifacts, and App Attest validation failures. See MASTG-KNOW-0135.
- Reverse engineering tool detection: Detect debuggers, instrumentation frameworks, hooking tools, and other runtime manipulation techniques, because virtual devices are often used together with these tools. See MASTG-KNOW-0087.
- Server-side enforcement: Use server-side checks for high-risk actions, such as App Attest validation, app integrity validation, request risk scoring, throttling, step-up verification, or denying access to sensitive features when multiple high-risk signals are present.
- Obfuscation and diversification: Obfuscate detection logic, scatter checks throughout the app, vary their timing, and avoid relying on a single static indicator. See MASTG-KNOW-0089.
- Graceful response handling: Avoid exposing precise detection reasons to the client. Prefer generic errors, reduced functionality, delayed responses, or server-side policy decisions that do not reveal which specific check was triggered.
These controls do not make execution in virtual devices impossible. Their goal is to increase the cost of analysis, reduce the reliability of automated large-scale testing, and make bypasses harder to maintain across app versions and environments.
|
|
MASTG-BEST-0054 Validate Input Parameters in Custom URL Scheme Handlers (iOS)
|
Validate and sanitize all URL parameters before using them in your custom URL scheme handler. Since any app on the device can open a custom URL scheme, treat all incoming parameter values as untrusted input. Convert to Expected TypesWhen a parameter represents a numeric value, convert it explicitly using Int.init-7l2mf) or Double.init-90wjl) and handle conversion failure gracefully. Never use the raw string from URLQueryItem.value directly in operations that expect a specific type. guard let amountString = components?.queryItems?.first(where: { $0.name == "amount" })?.value,
let amount = Int(amountString) else {
return
}
Check Bounds and RangesAfter type conversion, verify that the value falls within acceptable bounds before acting on it. For financial or resource-sensitive operations, enforce both minimum and maximum limits. guard amount > 0, amount <= 10000 else {
return
}
Sanitize String ParametersWithout sanitization, an attacker can craft URLs with malicious parameter values targeting different parts of the app: - Path traversal: a parameter like
path=../../private/secrets.txt can escape intended directories if used in file operations. Resolve paths with URL.standardized and verify the result stays within the expected base directory. See MASTG-BEST-0033 for secure file loading in WebViews. - Script injection: a parameter like
q=<script>alert(1)</script> can execute arbitrary JavaScript if rendered in a WKWebView. See MASTG-BEST-0034 for WebView input validation guidance. - Command or query injection: parameter values interpolated into shell commands, SQL queries, or predicate strings can alter their logic. Use parameterized queries and avoid string interpolation for constructing commands.
Use allowlists for expected values when the set of valid inputs is known. Reject any value that does not match rather than attempting to strip or escape individual characters.
|
|
MASTG-BEST-0055 Validate Source Application in Custom URL Scheme Handlers (iOS)
|
When a custom URL scheme triggers a privileged or irreversible action, check sourceApplication from UIOpenURLContext.options before processing the request. This allows you to verify the calling app's bundle ID against an allowlist. let allowedSources: Set<String> = ["com.example.myapp", "com.example.companion"]
guard let source = context.options.sourceApplication,
allowedSources.contains(source) else {
return
}
Check Both URL Delivery PathsWhen using the Scene lifecycle, URLs can arrive through two paths: scene(_:willConnectTo:options:)) for cold launches and scene(_:openURLContexts:)) for warm opens. Validate sourceApplication in both handlers to avoid leaving one path unprotected. Apple Developer Team LimitationApple only populates sourceApplication when the calling app belongs to the same Apple Developer Team. Apps from other teams or system apps (e.g. Safari, Notes) will have sourceApplication set to nil. This means source validation is most useful for restricting URL scheme triggers to your own app suite, not for identifying arbitrary third-party callers. Note For apps using pure SwiftUI with .onOpenURL), sourceApplication is not available. If source validation is required, use the Scene lifecycle with SceneDelegate instead.
|
|
MASTG-BEST-0056 Use Explicit Intents for Internal IPC (Android)
|
Use explicit intents when communicating between components within the same app. An explicit intent specifies the target component directly by package name or class name, ensuring the intent can only be delivered to the intended recipient and can't be intercepted by a third-party app through normal intent resolution. Java/KotlinSet the target package with Intent.setPackage) or target a specific component before sending the intent: // Explicit by package - restricts delivery to your own app
val intent = Intent("com.example.app.PROCESS_DATA").apply {
setPackage("com.example.app")
putExtra("key", "value")
}
startActivity(intent)
// Explicit by component - the most restrictive form
val intent = Intent(context, TargetActivity::class.java).apply {
putExtra("key", "value")
}
startActivity(intent)
Never send sensitive data (tokens, credentials, API keys) in an implicit intent. Android resolves implicit intents by matching installed apps that declare compatible <intent-filter> elements, so any matching app can become the selected recipient and receive the intent extras. Manifest ConfigurationFor internal components, ensure they are not inadvertently exposed to other applications. For detailed instructions on properly securing the AndroidManifest.xml, refer to MASTG-BEST-0052.
|
|
MASTG-BEST-0057 Sanitize Data Coming from External Components (Android)
|
All data received from external sources (such as Intent extras, activity results, or ContentProvider results) must be treated as untrusted and thoroughly sanitized before use. Failure to validate this data can lead to serious vulnerabilities, including arbitrary file access and path traversal. Specifically, applications must always validate URIs and associated metadata before reading from them, copying their content, or passing them to sensitive system APIs. Validate the URI schemePrefer content:// URIs over file:// URIs when processing externally supplied data. A content:// URI routes access through a ContentProvider when opened with ContentResolver.openInputStream), allowing provider-level access controls and URI grants to apply. A file:// URI is resolved directly as a filesystem path using the calling app's own process identity and permissions. This means a malicious responding app can return a file:// URI pointing at any path the calling app can access, which, depending on the permissions the app holds, may go well beyond its own private storage. See MASTG-KNOW-0138 for details on URI schemes in intent results. Sanitize Filenames Provided by External ComponentsWhen querying a ContentProvider for OpenableColumns.DISPLAY_NAME, sanitize the result before using it as a filename. A malicious provider can return a path-traversal sequence (such as ../lib/native.so) that redirects writes outside the intended directory. Use File.getName) via File(name).name to strip any directory components: fun sanitizeFileName(name: String): String {
return File(name).name // returns only the final path component
}
val rawName = getFileNameFromUri(uri) ?: "default.bin"
val safeName = sanitizeFileName(rawName)
Sanitize Externally Provided Paths Before File OperationsAvoid using paths or filenames received from an intent to construct an output location directly. A malicious responder could supply an absolute path (such as /sdcard/evil.apk) that writes to an unintended location. Always anchor the output to a directory you control, such as filesDir or cacheDir, and append only a sanitized filename: // Avoid: output path comes from intent data
val output = File(fileNameFromIntent)
// Prefer: fixed base dir with a sanitized filename
val output = File(context.filesDir, sanitizeFileName(fileNameFromIntent))
When exposing app-owned files to other apps, prefer FileProvider with narrow path mappings and temporary URI grants instead of sharing raw filesystem paths.
|
|
MASTG-BEST-0058 Restrict Native Functionality Exposed Through WebView Bridges (iOS)
|
When using WKWebView, native functionality can be exposed to JavaScript through message handlers registered via WKUserContentController.add(_:name:)). Any JavaScript running in the WebView can call window.webkit.messageHandlers.<name>.postMessage(...) to invoke the corresponding native handler. If the handler exposes sensitive operations or data without proper validation, an attacker who can run JavaScript in the WebView (for example through content injection or XSS) can abuse it. Minimize Exposed FunctionalityOnly expose the minimal native functionality that JavaScript actually needs. Avoid registering handlers that return sensitive data (such as credentials or API keys), trigger privileged operations, or allow arbitrary writes to storage. Handlers should implement narrow, purpose-built operations rather than generic dispatch mechanisms. Validate Message ContentAlways validate messages received in userContentController(_:didReceive:) before processing them. Check that the message body has the expected type and structure, and reject unexpected inputs. func userContentController(_ userContentController: WKUserContentController,
didReceive message: WKScriptMessage) {
guard let body = message.body as? [String: String],
let action = body["action"],
action == "allowedAction" else {
return // reject unexpected messages
}
// handle known action
}
Restrict Handler ScopeRemove message handlers when the WebView is no longer needed to prevent accidental reuse: webView.configuration.userContentController.removeScriptMessageHandler(forName: "bridge")
Consider Origin ValidationAlthough WKWebView doesn't expose a direct origin-based access control model for script message handlers (unlike the Android addWebMessageListener API), you can inspect WKScriptMessage.frameInfo and its securityOrigin to determine the source of the message. For handlers serving sensitive operations, verify that the message comes from an expected trusted origin before processing. Avoid Legacy UIWebView BridgesDon't use UIWebView and its JSContext or JSExport bridge mechanisms. UIWebView was deprecated in iOS 12. It always enables JavaScript and doesn't provide the same security controls as WKWebView. Migrate to WKWebView as described in MASTG-BEST-0032.
|
|
MASTG-BEST-0059 Render Sensitive UI as Native Views Over the WebView (iOS)
|
When a WKWebView needs to present sensitive UI, such as a credential picker, autofill suggestion, or payment confirmation, rendering that interface as HTML elements inside the WebView exposes it to any JavaScript running on the page. An attacker who can execute JavaScript in the WebView (for example, through XSS or content injection) can read, modify, or visually spoof those elements. The safer approach is to display sensitive information as a native element over the WebView. By using native components, the data remains entirely outside the DOM and is not accessible to JavaScript. Overlaying Native Views on DOM ElementsThe app can retrieve the coordinates of a specific HTML element and display a native view directly over this element specifically. This allows the app to maintain the look and feel of the web page while keeping the actual data secure in the native layer. To retrieve the coordinates safely, an isolated WKContentWorld can be used. Registering the script that reads DOM geometry in a custom world, separate from the page world, ensures that page JavaScript cannot override or intercept the script. For more details on using worlds for script isolation, see MASTG-BEST-0061.
|
|
MASTG-BEST-0060 Use Native Views for Sensitive Text Entry Over a WebView (iOS)
|
When a WKWebView contains an HTML <input type="password"> or any sensitive text field, the typed value is stored in the element's .value property. Any JavaScript running on the page, including injected XSS payloads, can read it with document.querySelector('input[type=password]').value. The page does not need a native bridge to do this. The safer approach is to intercept user focus on the sensitive field before any typing occurs, then present a native UITextField (configured with isSecureTextEntry = true) overlaid at the exact position of the HTML element. The user types into the native view and the value never enters the DOM. Detect Focus with an Isolated ScriptUse a WKUserScript registered in a custom WKContentWorld (MASTG-KNOW-0139) to listen for focus events on sensitive inputs. The script runs in an isolated world, so page JavaScript cannot override it or the bridge it uses: let appWorld = WKContentWorld.world(withName: "AppWorld")
config.userContentController.add(inputHandler, contentWorld: appWorld, name: "secureInput")
let script = WKUserScript(source: """
document.querySelectorAll('input[type="password"], input[data-sensitive]').forEach(el => {
el.addEventListener('focus', () => {
const r = el.getBoundingClientRect();
window.webkit.messageHandlers.secureInput.postMessage({
x: r.left, y: r.top, width: r.width, height: r.height
});
el.blur(); // prevent the system keyboard from appearing for this field
});
});
""", injectionTime: .atDocumentStart, forMainFrameOnly: true, in: appWorld)
config.userContentController.addUserScript(script)
The message carries only layout coordinates. No sensitive content crosses this channel. Overlay a Native Secure Input ViewPresent a UITextField directly over the WKWebView at the reported position: func userContentController(_ ucc: WKUserContentController,
didReceive message: WKScriptMessage) {
guard message.name == "secureInput",
let body = message.body as? [String: Double] else { return }
let frame = CGRect(x: body["x"] ?? 0, y: body["y"] ?? 0,
width: body["width"] ?? 200, height: body["height"] ?? 44)
let secureField = UITextField(frame: frame)
secureField.isSecureTextEntry = true
secureField.borderStyle = .roundedRect
secureField.becomeFirstResponder()
webView.superview?.addSubview(secureField)
}
Because the UITextField is a native view outside the WKWebView's rendering context, page JavaScript has no access to it or to the characters the user types. Send the Value NativelyOnce the user confirms the input (for example, on return key or a native button), send the value directly from Swift (to your own API, Keychain, or another native layer) without writing it back into the DOM: secureField.addTarget(self, action: #selector(submitSecureValue(_:)), for: .editingDidEndOnExit)
@objc func submitSecureValue(_ field: UITextField) {
guard let value = field.text else { return }
// Submit natively, never assign to a DOM element
authManager.submitPasscode(value)
field.removeFromSuperview()
}
If the downstream flow requires the page to proceed (for example, to submit a form), trigger the form submission from the isolated world using evaluateJavaScript(_:in:in:completionHandler:) rather than populating the password field's .value in the DOM. Do Not Write the Value Back into the DOMSetting a password input's .value from Swift (even from an isolated world) makes the value readable by page JavaScript. If the submission flow requires the page's form, consider bypassing the HTML form entirely and submitting the credential directly from native code.
|
|
MASTG-BEST-0061 Use WKContentWorld Isolation for DOM Inspection Scripts (iOS)
|
When an app uses evaluateJavaScript(_:completionHandler:)) or WKUserScript to read data from the DOM (for example, to extract form field values, account details, or page metadata), that code runs in the .page world by default. In the .page world, all built-in prototypes are shared with page JavaScript. A malicious script running on the page can override document.querySelector, Element.prototype.getAttribute, or any other native function before your inspection code runs, causing it to receive manipulated results. Use the content-world variants of these APIs (introduced in iOS 14, see MASTG-KNOW-0139) to run DOM inspection code in an isolated world where the prototype chain cannot be tampered with by page JavaScript. Use the Content World Variant of evaluateJavaScriptPrefer evaluateJavaScript(_:in:in:completionHandler:)), which accepts a WKContentWorld: let appWorld = WKContentWorld.world(withName: "AppWorld")
// Vulnerable: runs in the page world, prototype chain is shared with page JS
webView.evaluateJavaScript("document.getElementById('balance').textContent") { value, error in
process(value)
}
// Safe: runs in an isolated world, prototype chain is independent
webView.evaluateJavaScript("document.getElementById('balance').textContent",
in: nil,
in: appWorld) { result in
if case .success(let value) = result { process(value) }
}
In the isolated world, document.getElementById cannot be overridden by page JavaScript. Even if the page runs document.getElementById = () => fakeElement before your script executes, your isolated world's binding is unaffected. Validate DOM Data Before Acting on ItContent world isolation protects the inspection code itself from being hijacked, but it does not prevent the page from placing misleading content in the DOM. If an attacker controls the page, element text content or input values may be manipulated before your script reads them. Treat all values read from the DOM as untrusted input and validate them on the native side before acting on them in a security-relevant way.
|
|
MASTG-BEST-0062 Use WKScriptMessageHandlerWithReply to Return Data to JavaScript (iOS)
|
When a native bridge handler needs to return data to JavaScript, the common pattern of calling evaluateJavaScript:completionHandler:) with a callback string such as window.receiveData(...) injects the return value into the page's JavaScript context. Any page script can override that global function before the handler fires it and intercept the returned data. WKScriptMessageHandlerWithReply eliminates this by delivering the reply directly to the JavaScript Promise that initiated the call, within the calling content world, without touching any global page-world scope.
Replace the evaluateJavaScript Callback PatternThe old pattern injects data into the page world via a global function: // Avoid: return value is injected into page-world JavaScript
func userContentController(_ ucc: WKUserContentController,
didReceive message: WKScriptMessage) {
let secret = fetchSecret()
let js = "window.receiveSecret('\(secret)')"
message.webView?.evaluateJavaScript(js, completionHandler: nil)
}
Replace it with WKScriptMessageHandlerWithReply, which returns directly to the caller: // Preferred: reply goes directly to the awaiting Promise in the caller's world
func userContentController(_ ucc: WKUserContentController,
didReceive message: WKScriptMessage,
replyHandler: @escaping (Any?, String?) -> Void) {
let secret = fetchSecret()
replyHandler(secret, nil)
}
On the JavaScript side, the call becomes a simple await: // No global callback needed, the reply arrives as a resolved Promise value
const secret = await window.webkit.messageHandlers.bridge.postMessage({action: "getSecret"});
|
|
MASTG-BEST-0063 Use Immutable PendingIntents with Explicit Intents (Android)
|
When creating a PendingIntent, always use FLAG_IMMUTABLE and ensure the base intent is explicit (targets a specific component). For background on the PendingIntent API and its security model, see MASTG-KNOW-0024. Use FLAG_IMMUTABLEAlways set PendingIntent.FLAG_IMMUTABLE when creating a PendingIntent. This prevents a receiving app from modifying the intent's unfilled fields, which could otherwise be used to redirect the intent to a malicious component. val pendingIntent = PendingIntent.getActivity(
context,
requestCode,
intent,
PendingIntent.FLAG_IMMUTABLE // prevents modification by the receiver
)
FLAG_IMMUTABLE [must be always specified](https://developer.android.com/guide/components/intents-filters#DeclareMutabilityPendingIntent "must be always specified") on apps targeting Android 12 or higher for each PendingIntent object that the app creates.
Only use FLAG_MUTABLE when the receiving component explicitly needs to fill in intent fields that cannot be known in advance (for example, inline reply actions or app widget [Pending Intents](../Document/0x05h-Testing-Platform-Interaction.md#pending-intents) that require a call back into the app). Even then, set only the fields you expect the receiver to modify. Use Explicit IntentsThe base Intent wrapped in a PendingIntent must specify its target component explicitly (package, class, or both), so that only the intended app and component can receive it. // Explicit: specifies both package and class
val intent = Intent(context, TargetActivity::class.java).apply {
setPackage(context.packageName)
}
val pendingIntent = PendingIntent.getActivity(
context,
requestCode,
intent,
PendingIntent.FLAG_IMMUTABLE
)
Avoid using an implicit intent (one that specifies only an action or category), because any app on the device can respond to it and potentially hijack the PendingIntent. References
|
|
MASTG-BEST-0064 Use Safe APIs for Object Deserialization (iOS)
|
Use secure, class-restricted deserialization for object archives that can be influenced by an attacker. This includes archives received from files, IPC payloads, network responses, pasteboard data, app extensions, shared containers, or other storage locations outside the app's full control. For current Apple guidance, see Archives and Serialization, NSSecureCoding, and NSKeyedUnarchiver. Apple's archived Secure Coding Guide section on "Validating Input and Interprocess Communication" still provides useful background and examples. Use Secure Coding and Class-Restricted DecodingMake classes that participate in secure archives conform to NSSecureCoding and return true from supportsSecureCoding. Decode nested objects with class-restricted APIs such as decodeObject(of:forKey:)-roif). Enable secure coding when creating and reading archives. Use archivedData(withRootObject:requiringSecureCoding:)) with requiringSecureCoding set to true, and ensure requiresSecureCoding is enabled before decoding attacker-influenced data. Restrict Top-Level UnarchivingUse top-level unarchiving APIs that require the expected class or set of allowed classes, such as unarchivedObject(ofClass:from:)). When decoding collections, include both the collection type and the allowed element types in the allowed class set. Validate Decoded ValuesTreat decoded objects as input data. Validate their contents before using them in security-sensitive decisions, file paths, URLs, commands, authorization logic, or persistent application state.
|
|
MASTG-BEST-0065 Implementing Storage Integrity Checks on iOS (iOS)
|
Implement storage integrity checks in iOS apps to detect unauthorized modifications to data stored on the device (for example, in the Keychain, UserDefaults/NSUserDefaults, files, or databases). These checks raise the cost for attackers who try to tamper with the app's data, especially on jailbroken devices, through backups, or by directly manipulating the app's data directory. For detecting modifications to the app's own executable code, see MASTG-BEST-0067. Compute an HMAC over any data you store on the device before writing it, and verify the HMAC before reading. Use a key that is stored in the iOS Keychain with a strict accessibility setting (e.g., kSecAttrAccessibleWhenUnlockedThisDeviceOnly) so it cannot be extracted from a backup or transferred to another device. Apple's CryptoKit provides a modern, Swift-friendly API: import CryptoKit
import Security
func hmac(for data: Data, key: SymmetricKey) -> Data {
let mac = HMAC<SHA256>.authenticationCode(for: data, using: key)
return Data(mac)
}
func verify(data: Data, mac: Data, key: SymmetricKey) -> Bool {
let expected = HMAC<SHA256>.authenticationCode(for: data, using: key)
return Data(expected) == mac
}
Alternatively, use CCHmac from CommonCrypto for Objective-C or mixed codebases. If you also encrypt the data, follow the Encrypt-then-MAC pattern: encrypt first, then compute the HMAC over the ciphertext. Warning File storage integrity checks are bypassable if the attacker can extract the HMAC key from the Keychain (possible on a jailbroken device) or intercept the verification logic. Treat these as a defense-in-depth control rather than a standalone guarantee.
|
|
MASTG-BEST-0066 Implementing Storage Integrity Checks on Android (Android)
|
Implement storage integrity checks in Android apps to detect unauthorized modifications to data stored on the device (for example, in SharedPreferences, files, or databases). These checks raise the cost for attackers who try to tamper with stored data, especially on rooted devices, through backups, or by directly manipulating the app's data directory. Storage IntegrityCompute an HMAC over any data you store on the device before writing it, and verify the HMAC before reading it back. Use a key that is generated and stored in the Android Keystore so that it cannot be extracted from the app package or a backup. import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
fun hmac(data: ByteArray, key: ByteArray): ByteArray {
val mac = Mac.getInstance("HmacSHA256")
mac.init(SecretKeySpec(key, "HmacSHA256"))
return mac.doFinal(data)
}
fun verify(data: ByteArray, tag: ByteArray, key: ByteArray): Boolean {
return hmac(data, key).contentEquals(tag)
}
Alternatively, the Security framework provides java.security.Signature for asymmetric signing and verification of stored data when a public/private key pair is more appropriate than a shared secret. If you also encrypt the data, follow the Encrypt-then-MAC pattern: encrypt first, then compute the HMAC over the ciphertext. Warning Storage integrity checks are bypassable if the attacker can extract the HMAC key (for example, if it is hardcoded in the app or recoverable on a rooted device) or intercept the verification logic at runtime. Treat these as a defense-in-depth control rather than a standalone guarantee. See MASTG-KNOW-0036 for more information on SharedPreferences storage.
|
|
MASTG-BEST-0067 Implementing Source Code Integrity Checks on iOS (iOS)
|
Implement source code integrity checks in iOS apps to detect unauthorized modifications to the app binary. These checks raise the cost for attackers who try to tamper with the app, especially on jailbroken devices or when the app is re-signed with another certificate. The OS provides code signing to verify the authenticity and integrity of app binaries before launch. However, on jailbroken devices or when an attacker re-signs the app with their own certificate, this protection can be bypassed. To supplement the OS-level protection, implement runtime source code integrity checks. These checks parse the Mach-O binary structure to locate the __TEXT/__text section, compute a cryptographic hash over it, and compare the hash against a hardcoded or securely stored reference value (see MASTG-KNOW-0140 for an implementation example). Use a strong hash function such as SHA-256 (via CC_SHA256 from CommonCrypto) instead of MD5, which is cryptographically weak. Store the reference hash value in a location that is itself protected from modification (for example, hardcoded in an obfuscated form in the binary). Warning Runtime source code integrity checks are inherently bypassable on jailbroken devices. Attackers can hook the check itself, patch the reference hash, or use Frida to intercept file-system calls and return the original binary. These checks should be treated as a cost-raising measure, not a guarantee.
|
|
MASTG-BEST-0068 Secure Data Sharing Between App Extensions and Containing Apps (iOS)
|
When an app and its extensions share data through an App Group, the shared container is readable and writable by every member of the group, with no per-item access control between members (see MASTG-KNOW-0082). Choose the sharing channel based on the sensitivity of the data, and protect what you store. Prefer a Shared Keychain for SecretsStore credentials, tokens, and keys that both the app and an extension need in a shared Keychain Access Group (the keychain-access-groups entitlement), not in shared UserDefaults or a shared file container. The Keychain provides dedicated, access-controlled key storage with its own accessibility class. Set an appropriate accessibility attribute such as kSecAttrAccessibleWhenUnlockedThisDeviceOnly. Protect Sensitive Files in the Shared ContainerWhen sensitive data must live in the shared file container, apply Data Protection so its contents are encrypted while the device is locked. Write files with the NSFileProtectionComplete class: try data.write(to: sharedContainerURL, options: .completeFileProtection)
This applies to all shared storage, in the same way it applies to the app's private storage (see MASTG-TEST-0299). Minimize What You ShareLimit the shared container to the data each extension actually needs. Avoid placing whole datasets or secrets there when an extension only needs a subset, and grant each extension only the App Group identifiers required for its functionality.
|
|
MASTG-BEST-0069 Keep Sensitive Input on the System Keyboard (iOS)
|
Custom keyboards are app extensions that replace the system keyboard across all apps and, once granted "Full Access", can transmit what the user types off the device (see MASTG-KNOW-0082). For input that carries secrets, such as passwords, PINs, one-time passcodes, or payment data, keep the entry on the trusted system keyboard rather than relying on whichever keyboard the user has installed. Mark Sensitive Fields as Secure (Preferred)Set isSecureTextEntry to true on the UITextField/UITextView, or use a SwiftUI SecureField. iOS does not display third-party keyboards for secure fields, so the typed characters stay on the system keyboard. This is field-scoped, so it does not disrupt the user's keyboard choice elsewhere in the app, and it also masks the input and prevents keyboard caching. let pinField = UITextField()
pinField.isSecureTextEntry = true
Reject Custom Keyboards App-Wide (When Appropriate)For apps where no field should ever use a third-party keyboard (for example, high-assurance banking apps), reject the keyboard extension point in the app delegate using application(_:shouldAllowExtensionPointIdentifier:)). The system then uses the built-in keyboard throughout the app. func application(_ application: UIApplication,
shouldAllowExtensionPointIdentifier extensionPointIdentifier: UIApplication.ExtensionPointIdentifier) -> Bool {
if extensionPointIdentifier == .keyboard {
return false
}
return true
}
Note Use this app-wide control deliberately. It removes the user's ability to use accessibility-oriented or localized third-party keyboards anywhere in the app, so prefer per-field isSecureTextEntry for individual sensitive fields and reserve the app-wide restriction for apps that genuinely require it.
|
|
MASTG-BEST-0070 Verify Android App Links with autoVerify and Digital Asset Links (Android)
|
When your app handles http/https deep links, declare them as Android App Links so the OS verifies that your app owns the target domain. Without verification, any other app can register the same intent filter and intercept the links (see MASTG-KNOW-0019). Enable autoVerify on the Intent FilterSet android:autoVerify="true" on every <intent-filter> that declares an http/https deep link. This tells Android to confirm the domain association before routing matching links to your app. <intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" android:host="www.example.com" />
</intent-filter>
Publish a Valid Digital Asset Links FileHost a Digital Asset Links file at https://<domain>/.well-known/assetlinks.json that lists your app's package name and signing certificate fingerprint. The file must be: - Served over HTTPS, without redirects (a redirect from
http to https or example.com to www.example.com causes verification to fail). - Valid JSON that includes the target app's package.
- Present on every host declared in the intent filters, including each subdomain, and at the root domain when a wildcard host is used.
Verify the AssociationApp Links are only protective once verification succeeds. Confirm the state on a device with adb shell pm get-app-links <package> and re-trigger verification as needed. See MASTG-TECH-0174 for the full verification workflow. Warning Before Android 12 (API level 31), a single non-verifiable link (a missing autoVerify, an invalid Digital Asset Links file, or a custom URL scheme in a verified intent filter) can cause Android to skip verification for all of the app's App Links. Keep verified intent filters free of unverifiable entries.
Avoid Relying on Custom URL Schemes for Sensitive FlowsCustom URL schemes (for example, myapp://) are never verified by the OS and can be claimed by any app. Prefer verified App Links for any link that triggers a sensitive action or carries sensitive data. If you must accept a custom URL scheme, validate its input as untrusted (see MASTG-BEST-0071).
|
|
MASTG-BEST-0071 Validate Input Parameters in Deep Link and Custom URL Scheme Handlers (Android)
|
Validate and sanitize every value read from an incoming deep link before using it. Any app on the device can send an Intent that targets your handler, and Android provides no reliable way to identify the caller, so treat all parameters obtained from Intent.getData(), Uri.getQueryParameter(), Uri.getPathSegments(), or Uri.getLastPathSegment() as untrusted input (see MASTG-KNOW-0019). Convert to Expected TypesWhen a parameter represents a numeric value, convert it explicitly with toLongOrNull() or toIntOrNull() and handle the failure case. Never use the raw string returned by getQueryParameter() directly in an operation that expects a specific type. val amount = uri.getQueryParameter("amount")?.toLongOrNull()
?: return // reject missing or non-numeric values
Check Bounds and RangesAfter type conversion, verify that the value falls within acceptable limits before acting on it. For financial or resource-sensitive operations, enforce both a minimum and a maximum. if (amount <= 0 || amount > 10_000) return
Sanitize String ParametersWithout sanitization, a crafted URI can target different parts of the app: - Path traversal: a value like
path=../../databases/secrets.db can escape an intended directory if used in file operations. Resolve and verify the canonical path stays within the expected base directory. - Script injection: a value like
q=<script>alert(1)</script> can execute JavaScript if rendered in a WebView. See MASTG-TEST-0031. - Query or command injection: values interpolated into SQL queries or shell commands can alter their logic. Use parameterized queries and avoid string concatenation.
Prefer allowlists for parameters that select a resource or an action when the set of valid inputs is known. Reject any value that does not match rather than attempting to strip individual characters. Restrict the Handler SurfaceIf a deep link handler does not need to be reachable by other apps, set android:exported="false" on its activity. For links that trigger sensitive actions, prefer verified App Links (see MASTG-BEST-0070) over custom URL schemes.
|
|
MASTG-BEST-0072 Validate Input Parameters in Universal Link Handlers (iOS)
|
Validate and sanitize the path and query parameters of every incoming universal link before using them in security-sensitive operations. Universal link verification only proves that the request targets a domain your app is associated with (MASTG-KNOW-0080); it does not validate the rest of the URL. Anyone can craft a link to your verified domain with arbitrary path and query values and get the user to open it, so treat the webpageURL and its parameters as untrusted input. Apple makes this explicit in ["Supporting universal links in your app"](https://developer.apple.com/documentation/xcode/supporting-universal-links-in-your-app "Supporting universal links in your app"): universal links are an entry point into your app, so validate all URL parameters, discard malformed URLs, and limit the actions a link can trigger to those that do not put the user's data at risk. Confirm the Activity and Read the Verified URLHandle the activity only when its type is NSUserActivityTypeBrowsingWeb and read the URL from webpageURL, then parse it with URLComponents: guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
let url = userActivity.webpageURL,
let components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
return false
}
Convert to Expected TypesWhen a parameter represents a numeric value, convert it explicitly with Int.init-7l2mf) or Double.init-90wjl) and handle failure gracefully. Never use the raw string from URLQueryItem.value directly in operations that expect a specific type. guard let amountString = components.queryItems?.first(where: { $0.name == "amount" })?.value,
let amount = Int(amountString) else {
return false
}
Check Bounds and RangesAfter type conversion, verify the value falls within acceptable bounds before acting on it. For financial or resource-sensitive operations, enforce both minimum and maximum limits. guard amount > 0, amount <= 10000 else {
return false
}
Sanitize Path and String ParametersWithout sanitization, a crafted universal link can target different parts of the app: - Path traversal: a value like
path=../../private/secrets.txt can escape intended directories if used in file operations. Resolve paths with URL.standardized and verify the result stays within the expected base directory. See MASTG-BEST-0033 for secure file loading in WebViews. - Script injection: a value like
q=<script>alert(1)</script> can execute arbitrary JavaScript if rendered in a WKWebView. See MASTG-BEST-0034 for WebView input validation guidance. - Command or query injection: values interpolated into shell commands, SQL queries, or predicate strings can alter their logic. Use parameterized queries and avoid string interpolation for constructing commands.
Use allowlists for the path or for parameters that select a resource or action when the set of valid inputs is known. Reject any value that does not match rather than attempting to strip or escape individual characters. The same validation applies regardless of how the link is delivered, that is, through application(_:continue:restorationHandler:), scene(_:continue:), or SwiftUI's onContinueUserActivity(_:perform:)).
|
|
MASTG-BEST-0073 Properly Validate Server Trust in URLSessionDelegate and WKNavigationDelegate (iOS)
|
When an iOS app overrides the default certificate validation by implementing URLSessionDelegate.urlSession(_:didReceive:completionHandler:)) or WKNavigationDelegate.webView(_:didReceive:completionHandler:)), it takes full control of the server trust evaluation. An incorrect implementation that accepts credentials without calling SecTrustEvaluateWithError) bypasses certificate chain validation and hostname verification, leaving connections open to Machine-in-the-Middle (MITM) attacks. See "Performing manual server trust authentication" in the Apple Developer Documentation for more information. Prefer the Default ATS Trust EvaluationThe safest approach is to not implement urlSession(_:didReceive:completionHandler:) or webView(_:didReceive:completionHandler:) at all. When these methods are absent, the URL Loading System and WKWebView perform the full ATS-enforced server trust evaluation automatically. Override these methods only when the app has a specific justified requirement (for example, certificate pinning or connecting to a development server with a self-signed certificate). Even for certificate pinning, prefer Apple's declarative Identity Pinning, which lets you pin CA or leaf public keys directly in the Info.plist under NSPinnedDomains and is enforced automatically by ATS without any custom validation code (see MASTG-KNOW-0072). If a server presents an otherwise untrusted certificate, fix it server-side rather than weakening or replacing the system's trust evaluation in the app. Perform Explicit Server Trust EvaluationIf you must handle the challenge, always: - Confirm the challenge is of type
NSURLAuthenticationMethodServerTrust. - Obtain the
serverTrust object from challenge.protectionSpace.serverTrust. - Call
SecTrustEvaluateWithError and verify it returns true. - Call
completionHandler(.useCredential, URLCredential(trust: serverTrust)) only when evaluation succeeds. - Call
completionHandler(.cancelAuthenticationChallenge, nil) on any other challenge type or when evaluation fails.
|
|
MASTG-BEST-0074 Implementing Anti-Debugging Checks on iOS (iOS)
|
Implement anti-debugging checks in iOS apps that handle high-risk flows, and run those checks at startup and before or during sensitive operations instead of relying on a single startup check. Use anti-debugging as a defense-in-depth control. A local attacker who controls the device or app package can eventually bypass client-side checks through patching, instrumentation, or a modified runtime. The goal is to raise attacker effort, make bypasses harder to maintain, and feed risk signals into broader app and backend policy. Use Layered SignalsCombine multiple signal types from MASTG-KNOW-0085 instead of depending on one API. For example: - Use [
ptrace](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/ptrace.2.html "PTRACE(2)") and PT_DENY_ATTACH where this is acceptable for the app's distribution model. - Use process-state checks such as Apple's archived [
sysctl debugger detection example](https://developer.apple.com/library/archive/qa/qa1361/_index.html "Detecting the Debugger") as one reactive signal. - Add parent-process or Mach exception port checks where they fit the app's threat model.
Validate the implementation against the app's distribution requirements. Some low-level APIs used by anti-debugging implementations are not part of the public iOS SDK, and apps distributed through the App Store must comply with Apple's public API and review requirements. Check Sensitive FlowsRun anti-debugging checks close to security-relevant operations, such as: - key unwrapping or signing
- payment approval
- authentication or step-up authorization
- secrets access
- premium feature enforcement
- high-risk transaction submission
Avoid tight polling loops that waste battery or degrade performance. Prefer checkpoint-based checks before sensitive actions, with short periodic checks only while sensitive flows are active. Harden the Check and ResponseObfuscate anti-debugging logic and avoid centralizing every check behind a single named function. A single dispatch point is easier to hook or patch than several distributed checks. When the app detects a debugger, use a response that fits the risk of the protected flow. For example, terminate the sensitive operation, clear transient secrets from memory, require reauthentication, reduce functionality, or send a generic risk signal to the backend. Avoid exposing detailed detection reasons to the client because they help attackers tune bypasses. Test the checks in release builds. Debug-only code paths, checks that run only once at startup, or responses that can be bypassed by hooking one function provide limited resilience.
|
1.1 Nuorodos
1.2 Nustatyti reikalavimai
1.3 Susiję teisės aktai
2. Nustatyti reikalavimai
Reikalavimai
| Šaltinis |
Reikalavimas |
3. Susiję teisės aktai
Teisės aktai
| Šaltinis |
Reguliavimas |
- OWASP -
EN: Publications of the OWASP Foundation, https://owasp.org/. OWASP® is a registered trademark of the OWASP Foundation, Inc.; GRCA is not affiliated with, nor endorsed by, the OWASP Foundation. Only the versions published by OWASP are authoritative. - OWASP Application Security Verification Standard (ASVS) 5.0.0, May 2025, from OWASP/ASVS: © 2008-2025 The OWASP Foundation, licensed under CC BY-SA 4.0. Changes: divided into sections and converted into the GRCA format, the wording unchanged. These adaptations are shared under CC BY-SA 4.0 as well.
- OWASP Mobile Application Security Verification Standard (MASVS) v2.1.0, January 2024, from OWASP/masvs: © The OWASP Foundation, licensed under CC BY-SA 4.0. Changes: converted into the GRCA format, the wording unchanged. These adaptations are shared under CC BY-SA 4.0 as well.
- OWASP Mobile Application Security Weakness Enumeration (MASWE) v1.0.0, August 2026, from OWASP/maswe: © The OWASP Foundation, licensed under CC BY-SA 4.0. Changes: converted into the GRCA format, the wording unchanged, linked to the MASVS controls they map to. These adaptations are shared under CC BY-SA 4.0 as well.
- OWASP Mobile Application Security Testing Guide (MASTG) v2.0.0, June 2026, from OWASP/mastg: © The OWASP Foundation, licensed under CC BY-SA 4.0. The tests and best practices only, without code samples, images, tools or apps. Changes: converted into the GRCA format, the wording unchanged; references to other pages of the MASTG as links to mas.owasp.org; the weakness of each test in the numbering of MASWE v1 and linked to it. These adaptations are shared under CC BY-SA 4.0 as well.
- OWASP Software Assurance Maturity Model (SAMM) v2.2.0, July 2026, from owaspsamm/core: © The OWASP Foundation, licensed under CC BY-SA 4.0. Changes: converted into the GRCA format, the wording unchanged; short codes (G-SM-1-A) built from the model, the assessment questions as assessment procedures of their activities. These adaptations are shared under CC BY-SA 4.0 as well.
- OWASP Top 10:2025, from OWASP/Top10: © 2003-2025 The OWASP® Foundation, Inc., licensed under CC BY-SA 4.0. The ten categories, without the icons. Changes: converted into the GRCA format, the wording unchanged. These adaptations are shared under CC BY-SA 4.0 as well. The names of the mapped CWEs (Common Weakness Enumeration): © 2006–2026 The MITRE Corporation. License: The MITRE Corporation hereby grants you a non-exclusive, royalty-free license to use CWE for research, development, and commercial purposes. Any copy you make for such purposes is authorized on the condition that you reproduce MITRE’s copyright designation and this license in any such copy. See the CWE Terms of Use. CWE™ is a trademark of The MITRE Corporation.
DE: Veröffentlichungen der OWASP Foundation, https://owasp.org/. OWASP® ist eine eingetragene Marke der OWASP Foundation, Inc.; GRCA steht in keiner Verbindung zur OWASP Foundation und wird von ihr nicht unterstützt. Maßgeblich sind allein die von OWASP veröffentlichten Fassungen. - OWASP Application Security Verification Standard (ASVS) 5.0.0, Mai 2025, aus OWASP/ASVS: © 2008-2025 The OWASP Foundation, lizenziert unter CC BY-SA 4.0. Änderungen: in Abschnitte aufgeteilt und in das GRCA-Format umgewandelt, der Wortlaut unverändert. Diese Bearbeitungen stehen ebenfalls unter CC BY-SA 4.0.
- OWASP Mobile Application Security Verification Standard (MASVS) v2.1.0, Januar 2024, aus OWASP/masvs: © The OWASP Foundation, lizenziert unter CC BY-SA 4.0. Änderungen: in das GRCA-Format umgewandelt, der Wortlaut unverändert. Diese Bearbeitungen stehen ebenfalls unter CC BY-SA 4.0.
- OWASP Mobile Application Security Weakness Enumeration (MASWE) v1.0.0, August 2026, aus OWASP/maswe: © The OWASP Foundation, lizenziert unter CC BY-SA 4.0. Änderungen: in das GRCA-Format umgewandelt, der Wortlaut unverändert, mit den MASVS-Controls verknüpft, denen sie zugeordnet sind. Diese Bearbeitungen stehen ebenfalls unter CC BY-SA 4.0.
- OWASP Mobile Application Security Testing Guide (MASTG) v2.0.0, Juni 2026, aus OWASP/mastg: © The OWASP Foundation, lizenziert unter CC BY-SA 4.0. Nur die Tests und Best Practices, ohne Codebeispiele, Bilder, Werkzeuge und Apps. Änderungen: in das GRCA-Format umgewandelt, der Wortlaut unverändert; Verweise auf andere Seiten des MASTG als Links zu mas.owasp.org; die Schwachstelle jedes Tests in der Nummerierung der MASWE v1 und mit ihr verknüpft. Diese Bearbeitungen stehen ebenfalls unter CC BY-SA 4.0.
- OWASP Software Assurance Maturity Model (SAMM) v2.2.0, Juli 2026, aus owaspsamm/core: © The OWASP Foundation, lizenziert unter CC BY-SA 4.0. Änderungen: in das GRCA-Format umgewandelt, der Wortlaut unverändert; Kürzel (G-SM-1-A) aus dem Modell gebildet, die Assessment-Fragen als Prüfverfahren ihrer Aktivitäten. Diese Bearbeitungen stehen ebenfalls unter CC BY-SA 4.0.
- OWASP Top 10:2025, aus OWASP/Top10: © 2003-2025 The OWASP® Foundation, Inc., lizenziert unter CC BY-SA 4.0. Die zehn Kategorien, ohne die Symbole. Änderungen: in das GRCA-Format umgewandelt, der Wortlaut unverändert. Diese Bearbeitungen stehen ebenfalls unter CC BY-SA 4.0. Die Namen der zugeordneten CWEs (Common Weakness Enumeration): © 2006–2026 The MITRE Corporation. MITRE erlaubt die Nutzung für Forschung, Entwicklung und kommerzielle Zwecke, wenn jede Kopie den Urheberrechtsvermerk und die Lizenz enthält; maßgeblich ist der englische Wortlaut der Lizenz oben und die CWE Terms of Use. CWE™ ist eine Marke der MITRE Corporation.
|