Skip to content

Commit

Permalink
Add MASTG Mitigations support (#3081)
Browse files Browse the repository at this point in the history
* Rename and update mitigations using IDs and add index

* Update mitigations to tests metadata

* Add support for mitigations in cross-references and metadata generation

* Add mitigations section to documentation and update navigation

* Remove remediation section from MASTG-TEST-0204.md
  • Loading branch information
cpholguera authored Dec 2, 2024
1 parent 4962ff9 commit 3ca954b
Show file tree
Hide file tree
Showing 22 changed files with 176 additions and 71 deletions.
1 change: 1 addition & 0 deletions Document/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Start exploring the MASTG:
<a href="/MASTG/demos/" class="md-button md-button--primary" style="margin: 5px; min-width: 12em; text-align: center;">:material-flask-outline: Demos</a>
<a href="/MASTG/tools/" class="md-button md-button--primary" style="margin: 5px; min-width: 12em; text-align: center;">:octicons-tools-24: Tools</a>
<a href="/MASTG/apps/" class="md-button md-button--primary" style="margin: 5px; min-width: 12em; text-align: center;">:octicons-code-square-24: Apps</a>
<a href="/MASTG/mitigations/" class="md-button md-button--primary" style="margin: 5px; min-width: 12em; text-align: center;">:material-bandage: Mitigations (v2 Beta)</a>

<span style="color: darkgray; font-size: small"> :blue_heart:{ .pump } Support the project by purchasing the [OWASP MASTG on leanpub.com](https://leanpub.com/owasp-mastg). All funds raised through sales of this book go directly into the project budget and will be used to for technical editing and designing the book and fund production of future releases.</span>

Expand Down
56 changes: 53 additions & 3 deletions docs/hooks/add-cross-references.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,30 +27,42 @@ def gather_metadata(directory, id_key):
return metadata

def generate_cross_references():
weaknesses = gather_metadata("MASWE", "id")
tests = gather_metadata("MASTG/tests-beta", "id")
demos = gather_metadata("MASTG/demos", "id")

cross_references = {
"weaknesses": {},
"tests": {}
"tests": {},
"mitigations": {}
}

for test_id, test_meta in tests.items():
weakness_id = test_meta.get("weakness")
test_path = test_meta.get("path")
test_title = test_meta.get("title")
test_platform = test_meta.get("platform")
mitigations_ids = test_meta.get("mitigations")

# Create cross-references for weaknesses listing all tests that reference each weakness ID
if weakness_id:
if weakness_id not in cross_references["weaknesses"]:
cross_references["weaknesses"][weakness_id] = []
cross_references["weaknesses"][weakness_id].append({"id": test_id, "path": test_path, "title": test_title, "platform": test_platform})


# Create cross-references for mitigations listing all tests that reference each mitigation ID
if mitigations_ids:
for mitigation_id in mitigations_ids:
if mitigation_id not in cross_references["mitigations"]:
cross_references["mitigations"][mitigation_id] = []
cross_references["mitigations"][mitigation_id].append({"id": test_id, "path": test_path, "title": test_title, "platform": test_platform})

for demo_id, demo_meta in demos.items():
test_id = demo_meta.get("test")
demo_path = demo_meta.get("path")
demo_title = demo_meta.get("title")
demo_platform = demo_meta.get("platform")

# Create cross-references for tests listing all demos that reference each test ID
if test_id:
if test_id not in cross_references["tests"]:
cross_references["tests"][test_id] = []
Expand Down Expand Up @@ -81,6 +93,10 @@ def on_page_markdown(markdown, page, config, **kwargs):

if "MASWE-" in path:
weakness_id = meta.get('id')

# Add Tests section to weaknesses as buttons
# ORIGIN: Cross-references from this script

if weakness_id in cross_references["weaknesses"]:
tests = cross_references["weaknesses"][weakness_id]
meta['tests'] = tests
Expand All @@ -93,6 +109,10 @@ def on_page_markdown(markdown, page, config, **kwargs):

if "MASTG-TEST-" in path:
test_id = meta.get('id')

# Add Demos section to tests as buttons
# ORIGIN: Cross-references from this script

if test_id in cross_references["tests"]:
demos = cross_references["tests"][test_id]
meta['demos'] = demos
Expand All @@ -104,4 +124,34 @@ def on_page_markdown(markdown, page, config, **kwargs):

markdown += f"\n\n{demos_section}"

# Add Mitigations section to tests as a bullet point list with IDs, links are resolved in a separate hook
# ORIGIN: Test metadata

mitigations = meta.get('mitigations')
if mitigations:
mitigations_section = "## Mitigations\n\n"
for mitigation_id in mitigations:
mitigation_path = f"MASTG/mitigations/{mitigation_id}.md"
relPath = os.path.relpath(mitigation_path, os.path.dirname(path))
mitigations_section += f"- @{mitigation_id}\n"

markdown += f"\n\n{mitigations_section}"

if "MASTG-MITIG" in path:
mitig_id = meta.get('id')

# Add Tests section to mitigations as buttons
# ORIGIN: Cross-references from this script

if mitig_id in cross_references["mitigations"]:
mitigations = cross_references["mitigations"].get(mitig_id)
meta['mitigations'] = mitigations
if mitigations:
mitigations_section = "## Tests\n\n"
for mitigation in mitigations:
relPath = os.path.relpath(mitigation['path'], os.path.dirname(path))
mitigations_section += f"[{get_platform_icon(mitigation['platform'])} {mitigation['id']}: {mitigation['title']}]({relPath}){{: .mas-test-button}} "

markdown += f"\n\n{mitigations_section}"

return markdown
29 changes: 29 additions & 0 deletions docs/hooks/create_dynamic_tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,25 @@ def get_all_demos_beta():
demos.append(frontmatter)
return demos

def get_all_mitigations_beta():

mitigations = []

for file in glob.glob("docs/MASTG/mitigations/**/MASTG-MITIG-*.md", recursive=True):
with open(file, 'r') as f:
content = f.read()

frontmatter = next(yaml.load_all(content, Loader=yaml.FullLoader))

frontmatter['path'] = f"/MASTG/mitigations/{os.path.splitext(os.path.relpath(file, 'docs/MASTG/mitigations'))[0]}"
mitigation_id = frontmatter['id']
frontmatter['id'] = mitigation_id
frontmatter['title'] = f"@{mitigation_id}"
frontmatter['platform'] = get_platform_icon(frontmatter['platform'])

mitigations.append(frontmatter)
return mitigations

def reorder_dict_keys(original_dict, key_order):
return {key: original_dict.get(key, "N/A") for key in key_order}

Expand Down Expand Up @@ -303,6 +322,16 @@ def on_page_markdown(markdown, page, **kwargs):

return append_to_page(markdown, list_of_dicts_to_md_table(demos_beta_columns_reordered, column_titles))

elif path.endswith("mitigations/index.md"):
# mitigations-beta/index.md

column_titles = {'id': 'ID', 'title': 'Title', 'platform': "Platform"}

mitigations_beta = get_all_mitigations_beta()
mitigations_beta_columns_reordered = [reorder_dict_keys(mitigation, column_titles.keys()) for mitigation in mitigations_beta]

return append_to_page(markdown, list_of_dicts_to_md_table(mitigations_beta_columns_reordered, column_titles))

elif path.endswith("tools/index.md"):

# tools/index.md
Expand Down
6 changes: 3 additions & 3 deletions docs/hooks/resolve_references.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

log = logging.getLogger('mkdocs')

mapping = {"TECH":{}, "TOOL":{}, "TEST": {}, "APP": {}, "MASWE": {}, "MASVS": {}, "DEMO": {}}
mapping = {"TECH":{}, "TOOL":{}, "TEST": {}, "APP": {}, "MASWE": {}, "MASVS": {}, "DEMO": {}, "MITIG": {}}

@mkdocs.plugins.event_priority(-50)
def on_page_markdown(markdown, page, config, **kwargs):
Expand All @@ -17,7 +17,7 @@ def on_page_markdown(markdown, page, config, **kwargs):

icons_for_text = {key.upper(): f":{value.replace('/', '-')}: " for key, value in icons.items()}

pageRefs = {"TECH": [], "TOOL": [], "TEST": [], "APP": [], "MASWE": [], "MASVS": [], "DEMO": []}
pageRefs = {"TECH": [], "TOOL": [], "TEST": [], "APP": [], "MASWE": [], "MASVS": [], "DEMO": [], "MITIG": []}

def replaceReference(match):
refType = match.group(2)
Expand Down Expand Up @@ -57,7 +57,7 @@ def replaceReferenceMASVS(match):
return f"_[{icon}{mapping[refType][match]['title']}]({mapping[refType][match]['file']})_"


updated_markdown = re.sub(r'@(MASTG-(TECH|TOOL|TEST|APP|DEMO)-\d{3,})', replaceReference, markdown)
updated_markdown = re.sub(r'@(MASTG-(TECH|TOOL|TEST|APP|DEMO|MITIG)-\d{3,})', replaceReference, markdown)
updated_markdown = re.sub(r'@(MASWE-\d{3,})', replaceReferenceMASWE, updated_markdown)
updated_markdown = re.sub(r'@(MASVS-\w+)', replaceReferenceMASVS, updated_markdown)

Expand Down
2 changes: 1 addition & 1 deletion docs/hooks/update_titles.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def set_page_icon(page, config, component_type=None):
def on_page_markdown(markdown, page, config, **kwargs):
path = page.file.src_uri

if any(keyword in path for keyword in ["MASTG-TEST-", "MASTG-TOOL-", "MASTG-TECH-", "MASTG-APP-", "MASTG-DEMO-"]):
if any(keyword in path for keyword in ["MASTG-TEST-", "MASTG-TOOL-", "MASTG-TECH-", "MASTG-APP-", "MASTG-DEMO-", "MASTG-MITIG-"]):
# TODO the component ID is the file basename without the extension; ensure that all components have id in the future
page.meta['id'] = path.split('/')[-1].split('.')[0]
component_type = page.meta['id'].split('-')[1].lower()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
---
title: Use Secure Random Number Generators APIs
alias: android-use-secure-random
id: MASTG-MITIG-0001
platform: android
---

Expand Down
12 changes: 11 additions & 1 deletion mitigations/use-proguard.md → mitigations/MASTG-MITIG-0002.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
---
title: Use ProGuard to Remove Logging Code
title: Remove Logging Code
alias: remove-logging-code
id: MASTG-MITIG-0002
platform: android
---

Ideally, a release build shouldn't use any logging functions, making it easier to assess sensitive data exposure.

## Using ProGuard

While 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")):

```default
Expand Down Expand Up @@ -57,3 +63,7 @@ SecureLog.v("Private key [byte format]: ", key);
```

Then configure ProGuard to strip its calls.

## Custom Logging

You can implement a custom logging facility and disable it at once only for the release builds.
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
---
title: Comply with Privacy Regulations and Best Practices
alias: comply-with-privacy-regulations
id: MASTG-MITIG-0003
platform: android
---

Expand Down
11 changes: 11 additions & 0 deletions mitigations/MASTG-MITIG-0004.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
title: Exclude Sensitive Data from Backups
alias: exclude-sensitive-data-from-backups
id: MASTG-MITIG-0004
platform: 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](https://developer.android.com/identity/data/keyvaluebackup#BackupAgent) accordingly.
12 changes: 12 additions & 0 deletions mitigations/MASTG-MITIG-0005.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
title: Use Secure Encryption Modes
alias: use-secure-encryption-modes
id: MASTG-MITIG-0005
platform: android
---

Replace insecure encryption modes with secure block cipher modes such as [AES-GCM or AES-CCM](https://csrc.nist.gov/pubs/sp/800/38/d/final) 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](https://developer.android.com/privacy-and-security/cryptography).
26 changes: 26 additions & 0 deletions mitigations/MASTG-MITIG-0006.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
title: Use Up-to-Date APK Signing Schemes
alias: use-up-to-date-apk-signing-schemes
id: MASTG-MITIG-0006
platform: 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](https://developer.android.com/about/versions/11/features#incremental) 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:

```default
// build.gradle
android {
...
signingConfigs {
config {
...
enableV3Signing true
enableV4Signing true
}
}
}
```
11 changes: 11 additions & 0 deletions mitigations/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
hide: toc
title: Mitigations (v2 - Beta)
status: new
---

??? info "About the MASTG Mitigations"

The MASTG Mitigations are a collection of specific strategies and best practices that can be used to mitigate security and privacy risks in mobile apps.

Each mitigation is designed to be simple and focused and may apply to one or multiple tests in the MASTG.
5 changes: 5 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ nav:
# - ... | flat | MASTG/demos/ios/MASVS-RESILIENCE/**/MASTG-DEMO-*.md
# - MASVS-PRIVACY:
# - ... | flat | MASTG/demos/ios/MASVS-PRIVACY/**/MASTG-DEMO-*.md
- Mitigations:
- MASTG/mitigations/index.md
- ... | flat | MASTG/mitigations/*.md
- Techniques:
- MASTG/techniques/index.md
- Generic:
Expand Down Expand Up @@ -249,6 +252,7 @@ theme:
app: octicons/code-square-24
demo: material/flask-outline
tech: material/magic-staff # fontawesome/solid/wand-magic-sparkles
mitig: material/bandage
maswe: octicons/shield-24
masvs: simple/owasp
features:
Expand Down Expand Up @@ -374,6 +378,7 @@ extra:
tech: tech
maswe: maswe
masvs: masvs
mitig: mitig
status:
draft: This page is in draft.
new: New in this beta!
2 changes: 1 addition & 1 deletion src/scripts/structure_mastg.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ set -euo pipefail
mkdir -p docs/MASTG
mkdir -p docs/MASWE

directories=("tests" "techniques" "tools" "apps" "tests-beta" "demos" "rules")
directories=("tests" "techniques" "tools" "apps" "tests-beta" "demos" "rules" "mitigations")

for dir in "${directories[@]}"; do
rm -rf "docs/MASTG/$dir"
Expand Down
3 changes: 1 addition & 2 deletions tests-beta/android/MASVS-CRYPTO/MASTG-TEST-0204.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ platform: android
title: Insecure Random API Usage
id: MASTG-TEST-0204
type: [static]
mitigations:
- android-use-secure-random
mitigations: [MASTG-MITIG-0001]
prerequisites:
- identify-sensitive-data
- identify-security-relevant-contexts
Expand Down
3 changes: 1 addition & 2 deletions tests-beta/android/MASVS-CRYPTO/MASTG-TEST-0205.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ platform: android
title: Non-random Sources Usage
id: MASTG-TEST-0205
type: [static]
mitigations:
- android-use-secure-random
mitigations: [MASTG-MITIG-0001]
prerequisites:
- identify-sensitive-data
- identify-security-relevant-contexts
Expand Down
9 changes: 1 addition & 8 deletions tests-beta/android/MASVS-CRYPTO/MASTG-TEST-0232.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ platform: android
id: MASTG-TEST-0232
type: [static, dynamic]
weakness: MASWE-0020
mitigations: [MASTG-MITIG-0005]
---

## Overview
Expand Down Expand Up @@ -42,11 +43,3 @@ The output should contain a list of locations where insecure or deprecated encry
## Evaluation

The test case fails if any insecure encryption modes are identified in the app.

## Mitigation

Replace insecure encryption modes with secure block cipher modes such as [AES-GCM or AES-CCM](https://csrc.nist.gov/pubs/sp/800/38/d/final) 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](https://developer.android.com/privacy-and-security/cryptography).
Loading

0 comments on commit 3ca954b

Please sign in to comment.