Merge pull request #10106 from egregius313/egregius313/android-backup-allowed

Java: Query to detect Android backup allowed
This commit is contained in:
Edward Minnix III
2022-09-12 11:14:03 -04:00
committed by GitHub
31 changed files with 279 additions and 2 deletions

View File

@@ -0,0 +1,4 @@
---
category: feature
---
* Added a new predicate, `allowsBackup`, in the `AndroidApplicationXmlElement` class. This predicate detects if the application element does not disable the `android:allowBackup` attribute.

View File

@@ -72,6 +72,56 @@ class AndroidApplicationXmlElement extends XmlElement {
* Holds if this application element has explicitly set a value for its `android:permission` attribute.
*/
predicate requiresPermissions() { this.getAnAttribute().(AndroidPermissionXmlAttribute).isFull() }
/**
* Holds if this application element does not disable the `android:allowBackup` attribute.
*
* https://developer.android.com/guide/topics/data/autobackup
*/
predicate allowsBackup() {
not this.getFile().(AndroidManifestXmlFile).isInBuildDirectory() and
(
// explicitly sets android:allowBackup="true"
this.allowsBackupExplicitly()
or
// Manifest providing the main intent for an application, and does not explicitly
// disallow the allowBackup attribute
this.providesMainIntent() and
// Check that android:allowBackup="false" is not present
not exists(AndroidXmlAttribute attr |
this.getAnAttribute() = attr and
attr.getName() = "allowBackup" and
attr.getValue() = "false"
)
)
}
/**
* Holds if this application element sets the `android:allowBackup` attribute to `true`.
*
* https://developer.android.com/guide/topics/data/autobackup
*/
private predicate allowsBackupExplicitly() {
exists(AndroidXmlAttribute attr |
this.getAnAttribute() = attr and
attr.getName() = "allowBackup" and
attr.getValue() = "true"
)
}
/**
* Holds if the application element contains a child element which provides the
* `android.intent.action.MAIN` intent.
*/
private predicate providesMainIntent() {
exists(AndroidActivityXmlElement activity |
activity = this.getAChild() and
exists(AndroidIntentFilterXmlElement intentFilter |
intentFilter = activity.getAChild() and
intentFilter.getAnActionElement().getActionName() = "android.intent.action.MAIN"
)
)
}
}
/**

View File

@@ -0,0 +1,45 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>In the Android manifest file, you can use the <code>android:allowBackup</code> attribute of the <code>application</code> element to define whether the
application will have automatic backups or not.</p>
<p>If your application uses any sensitive data, you should disable automatic backups to prevent attackers from extracting it.</p>
</overview>
<recommendation>
<p>For Android applications which process sensitive data, set <code>android:allowBackup</code> to <code>false</code> in the manifest
file.</p>
<p>Note: Since Android 6.0 (Marshmallow), automatic backups for applications are switched on by default.
</p>
</recommendation>
<example>
<p>In the following two (bad) examples, the <code>android:allowBackup</code> setting is enabled:</p>
<sample src="AllowBackupTrue.xml" />
<sample src="AllowBackupEmpty.xml"/>
<p>In the following (good) example, <code>android:allowBackup</code> is set to <code>false</code>:</p>
<sample src="AllowBackupFalse.xml"/>
</example>
<references>
<li>
Android Documentation:
<a href="https://developer.android.com/guide/topics/data/autobackup#EnablingAutoBackup">Back up user data with Auto Backup</a>
</li>
<li>
OWASP Mobile Security Testing Guide:
<a href="https://github.com/OWASP/owasp-mstg/blob/b7a93a2e5e0557cc9a12e55fc3f6675f6986bb86/Document/0x05d-Testing-Data-Storage.md#backups">
Android Backups
</a>
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,18 @@
/**
* @name Application backup allowed
* @description Allowing application backups may allow an attacker to extract sensitive data.
* @kind problem
* @problem.severity recommendation
* @security-severity 7.5
* @id java/android/backup-enabled
* @tags security
* external/cwe/cwe-312
* @precision very-high
*/
import java
import semmle.code.xml.AndroidManifest
from AndroidApplicationXmlElement androidAppElem
where androidAppElem.allowsBackup()
select androidAppElem, "Backups are allowed in this Android application."

View File

@@ -0,0 +1,7 @@
<manifest ... >
<!-- BAD: no 'android:allowBackup' set, defaults to 'true' -->
<application>
<activity ... >
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,8 @@
<manifest ... >
<!-- GOOD: 'android:allowBackup' set to 'false' -->
<application
android:allowBackup="false">
<activity ... >
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,8 @@
<manifest ... >
<!-- BAD: 'android:allowBackup' set to 'true' -->
<application
android:allowBackup="true">
<activity ... >
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,4 @@
---
category: newQuery
---
* Added a new query, `java/android/backup-enabled`, to detect if Android applications allow backups.

View File

@@ -0,0 +1,2 @@
// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/google-android-9.0.0
// codeql-extractor-kotlin-options: ${testdir}/../../../../../stubs/google-android-9.0.0

View File

@@ -0,0 +1,2 @@
| TestExplicitlyEnabled/AndroidManifest.xml:6:5:27:19 | application | Backups are allowed in this Android application. |
| TestMissing/AndroidManifest.xml:6:5:27:19 | application | Backups are allowed in this Android application. |

View File

@@ -0,0 +1,3 @@
class AllowBackupEnabledTest {
}

View File

@@ -0,0 +1 @@
Security/CWE/CWE-312/AllowBackupAttributeEnabled.ql

View File

@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapplication" />

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.myapplication">
<!-- Safe: 'android:allowBackup' explicitly disabled --> <application
android:allowBackup="false"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MyApplication"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.MyApplication.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.myapplication">
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MyApplication"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.MyApplication.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapplication" >
<!-- Safe: application element does not provide the MAIN intent --> <application android:supportsRtl="true">
</application>
</manifest>

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.myapplication">
<application
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MyApplication"
tools:targetApi="31">
<activity
android:name=".ItemDetailHostActivity"
android:exported="true"
android:label="@string/app_name"
android:resizeableActivity="true"
tools:targetApi="24">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.myapplication">
<!-- Safe: files in the build directory are ignored --> <application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MyApplication"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.MyApplication.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,2 @@
// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/google-android-9.0.0
// codeql-extractor-kotlin-options: ${testdir}/../../../../../stubs/google-android-9.0.0

View File

@@ -1,2 +0,0 @@
// semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/google-android-9.0.0
// codeql-extractor-kotlin-options: ${testdir}/../../../stubs/google-android-9.0.0