Skip to content

Commit

Permalink
feat(305172): add MobSF security scan on android and iOS builds for s…
Browse files Browse the repository at this point in the history
…taging and prod
  • Loading branch information
Arieldelossantos committed Jul 11, 2024
1 parent cb75a04 commit b6ee09a
Show file tree
Hide file tree
Showing 7 changed files with 279 additions and 5 deletions.
20 changes: 20 additions & 0 deletions build/azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,16 @@ stages:
applicationEnvironment: Staging
deploymentEnvironment: TestFlight

# MOBSF SECURITY SCAN STAGING
- stage: Security_Scan_Build_Staging
dependsOn: Build_Staging
jobs:
- template: stage-security-scan.yml
parameters:
applicationEnvironment: Staging
enableIosSecurityScan: true
enableAndroidSecurityScan: true

- stage: Build_Production
dependsOn: Build_Staging
condition: and(succeeded(), eq(variables['IsPullRequestBuild'], 'false'))
Expand Down Expand Up @@ -138,6 +148,16 @@ stages:
appCenterServiceConnectionName: $(AppCenterServiceConnection)
appCenterDistributionGroup: $(AppCenterDistributionGroup)

# MOBSF SECURITY SCAN PRODUCTION
- stage: Security_Scan_Build_Production
dependsOn: Build_Production
jobs:
- template: stage-security-scan.yml
parameters:
applicationEnvironment: Production
enableIosSecurityScan: true
enableAndroidSecurityScan: true

- stage: AppStore
condition: and(succeeded(), eq(variables['IsPullRequestBuild'], 'false'))
dependsOn: Build_Production
Expand Down
38 changes: 38 additions & 0 deletions build/stage-security-scan.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
parameters:
- name: applicationEnvironment
type: string
default: ''
- name: enableIosSecurityScan
type: boolean
default: false
- name: enableAndroidSecurityScan
type: boolean
default: false

jobs:
- job: OnLinux_iOS_SecurityScan
condition: eq(${{parameters.enableIosSecurityScan}}, true)
dependsOn: []
pool:
vmImage: $(ubuntuHostedAgentImage)
steps:
- template: templates/mobsf-scan.yml
parameters:
platform: 'iOS'
fileExtension: $(ipaFileExtension)
mobSfApiKey: $(mobSfApiKey)
artifactName: '$(iOSArtifactName)_${{ parameters.applicationEnvironment }}'

- job: OnLinux_Android_SecurityScan
condition: eq(${{parameters.enableAndroidSecurityScan}}, true)
dependsOn: []
pool:
vmImage: $(ubuntuHostedAgentImage)
steps:
- template: templates/mobsf-scan.yml
parameters:
platform: 'android'
fileExtension: $(aabFileExtension)
mobSfApiKey: $(mobSfApiKey)
artifactName: '$(AndroidArtifactName)_${{ parameters.applicationEnvironment }}'

6 changes: 3 additions & 3 deletions build/steps-build-ios.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ steps:
bannerVersionNumberText: '$(MajorMinorPatch)'

- task: FlutterBuild@0
displayName: Build Project for Release
displayName: Build Project for Release
inputs:
target: 'ios'
buildName: '$(MajorMinorPatch)'
Expand All @@ -103,7 +103,7 @@ steps:
condition: failed()

- task: Xcode@5
condition: and(succeeded(), eq(variables['IsPullRequestBuild'], 'false'))
condition: succeeded()
displayName: 'Xcode Archive iOS'
inputs:
actions: 'archive'
Expand All @@ -122,7 +122,7 @@ steps:
provisioningProfileName: '$(provisioningProfile.provisioningProfileName)'

- task: CopyFiles@2
condition: and(succeeded(), eq(variables['IsPullRequestBuild'], 'false'))
condition: succeeded()
displayName: 'Copy Binary Files'
inputs:
sourceFolder: '${{ parameters.pathToSrc }}/app'
Expand Down
149 changes: 149 additions & 0 deletions build/templates/mobsf-scan.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
parameters:
- name: mobSfApiKey
type: string
default: $(mobSfApiKey)
- name: artifactName
type: string
default: ''
- name: fileExtension
type: string
default: ''
- name: platform
type: string
default: ''

steps:
- task: DownloadPipelineArtifact@1
inputs:
buildType: 'current'
downloadType: 'single'
artifactName: "${{parameters.artifactName}}"
downloadPath: '$(System.ArtifactsDirectory)'
condition: succeeded()

- task: DockerInstaller@0
displayName: 'Install Docker'
inputs:
dockerVersion: $(DockerVersion)
condition: succeeded()

- script: docker pull opensecurity/mobile-security-framework-mobsf:latest
displayName: 'Pull MobSF Docker Image'
condition: succeeded()

- script: docker run -d -it --rm -e MOBSF_API_KEY='${{parameters.mobSfApiKey}}' -e DATA_UPLOAD_MAX_MEMORY_SIZE=209715200 -p 8000:8000 opensecurity/mobile-security-framework-mobsf:latest
displayName: 'Run MobSF Docker Image'
condition: succeeded()

- script: ls -R "$(System.ArtifactsDirectory)"
displayName: 'List Downloaded Artifacts'

- task: PowerShell@2
displayName: 'Upload file to MobSF'
inputs:
targetType: 'inline'
script: |
$FILENAME = Get-ChildItem -Path "$(System.ArtifactsDirectory)/" -File | Select-Object -First 1 -ExpandProperty Name
Write-Host "Filename: $FILENAME"
$file = "$(System.ArtifactsDirectory)/$FILENAME"
Write-Host "Uploading file $file to MobSF..."
# Check if the server is up and running
$serverIsRunning = $false
$retryCount = 0
while (-not $serverIsRunning -and $retryCount -lt 10) {
$response = curl --url http://127.0.0.1:8000/api/v1/scans -H "Authorization: ${{parameters.mobSfApiKey}}"
if ($response.StatusCode -eq 200) {
Write-Host "MobSF server is up and running"
$serverIsRunning = $true
} else {
Write-Host "Waiting for the MobSF server to start..."
$retryCount++
Start-Sleep -Seconds 5
}
}
$uploadResponse = curl -X POST -F "file=@$file;type=application/octet-stream" http://127.0.0.1:8000/api/v1/upload -H "Authorization: ${{parameters.mobSfApiKey}}"
$uploadResponseJson = $uploadResponse | ConvertFrom-Json
$hash = $uploadResponseJson.hash
echo "##vso[task.setvariable variable=fileHash]$hash"
Write-Host "Uploaded file hash: $hash"
Write-Host "File uploaded to MobSF successfully"
condition: succeeded()

- task: PowerShell@2
displayName: 'Run MobSF Scan'
inputs:
targetType: 'inline'
script: |
Write-Host "MobSF Scan started"
$hash = "$(fileHash)"
$scanUrl = "http://127.0.0.1:8000/api/v1/scan"
Write-Host "Scanning Uploaded file hash: $hash"
$headers = @{
"Authorization" = ${{parameters.mobSfApiKey}}
}
$scanBody = @{
"scan_type" = "${{parameters.fileExtension}}"
"hash" = $hash # use the hash from the upload response
}
$response = Invoke-RestMethod -Uri $scanUrl -Method Post -Headers $headers -Body $scanBody
Write-Host "Scan completed"
condition: succeeded()

- task: PowerShell@2
displayName: 'Download MobSF PDF report'
inputs:
targetType: 'inline'
script: |
Write-Host "Downloading MobSF PDF report..."
$hash = "$(fileHash)"
Write-Host "File hash: $hash"
$reportUrl = "http://127.0.0.1:8000/api/v1/download_pdf"
$headers = @{
"Authorization" = "${{parameters.mobSfApiKey}}"
}
$reportBody = @{
"hash" = $hash # use the hash from the upload response
}
$directoryPath = "${{parameters.artifactName}}/${{parameters.platform}}"
if (!(Test-Path -Path $directoryPath)) {
New-Item -ItemType Directory -Path $directoryPath | Out-Null
}
$pdfFilePath = "$directoryPath/report.pdf"
Invoke-WebRequest -Uri $reportUrl -Method Post -Headers $headers -Body $reportBody -OutFile $pdfFilePath
Write-Host "PDF report downloaded to $pdfFilePath"
condition: succeeded()

- task: PowerShell@2
displayName: 'Download MobSF Json report'
inputs:
targetType: 'inline'
script: |
Write-Host "Downloading MobSF Json report..."
$hash = "$(fileHash)"
Write-Host "File hash: $hash"
$reportUrl = "http://127.0.0.1:8000/api/v1/report_json"
$headers = @{
"Authorization" = "${{parameters.mobSfApiKey}}"
}
$reportBody = @{
"hash" = $hash # use the hash from the upload response
}
$reportResponse = Invoke-RestMethod -Uri $reportUrl -Method Post -Headers $headers -Body $reportBody
Write-Host "Response: $reportResponse"
$jsonFilePath = "${{parameters.artifactName}}/${{parameters.platform}}/Report.json"
$reportResponse | ConvertTo-Json | Out-File -FilePath $jsonFilePath
Write-Host "JSON report downloaded to $jsonFilePath"
condition: succeeded()

- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact'
inputs:
PathtoPublish: '${{parameters.artifactName}}/${{parameters.platform}}'
ArtifactName: ${{parameters.artifactName}}_Security_Reports
publishLocation: 'Container'

- task: PostBuildCleanup@3
displayName: 'Post-Build Cleanup: Cleanup files to keep build server clean!'
condition: always()
13 changes: 12 additions & 1 deletion build/variables.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,17 @@
InternalKeyProperties: com.nventive.internal.flutterapptemplate.key.properties # This is the internal key properties used for internal builds.
GooglePlayKeystore: com.nventive.flutterapptemplate.jks # This is the official keystore used for Google Play.
GooglePlayKeyProperties: com.nventive.flutterapptemplate.key.properties # This is the official key properties used for Google Play.
aabFileExtension: aab # This is the file extension for Android App Bundles.

# iOS.
InternalProvisioningProfile: com.nventive.internal.flutterapptemplate.mobileprovision # This is the internal provisioning profile for internal builds.
InternalExportOptions: com.nventive.internal.flutterapptemplate.exportOptions.plist # This is the export options file for internal builds.
InternalCertificate: nventive.p12 # This is the certificate from the nventive Apple account used to sign internal builds.
AppStoreProvisioningProfile: com.nventive.flutterapptemplate.mobileprovision # This is the client provisioning profile for the AppStore (Production distribution).
AppStoreExportOptions: com.nventive.flutterapptemplate.exportOptions.plist # This is the export options file for the AppStore (Production distribution) builds.
AppStoreCertificate: nventive.p12 # This is the client production certificate used to sign AppStore builds.

ipaFileExtension: ipa # This is the file extension for iOS IPA files.

# Firebase
InternalFirebaseJson: firebase-flutter-internal.json
InternalFirebaseOptionsDart: firebase_options-flutter-internal.dart
Expand Down Expand Up @@ -69,9 +72,17 @@
# Flutter version.
FlutterVersion: '3.22.1'

# Docker container to run MobSF.
DockerVersion: '25.0.5'

# MobSF Auth key.
# This key is used to authenticate the MobSF API installed on the created Docker instance, can use any random key even a Guid.
mobSfApiKey: '8181'

# Virtual machine images.
windowsHostedAgentImage: 'windows-2022'
macOSHostedAgentImage: 'macOS-13'
ubuntuHostedAgentImage: 'ubuntu-22.04'

# Name of the folder where the artefacts will be placed. Variable used in build and release phases.
# We make seperate folders so that releases can each download only the folder they need.
Expand Down
53 changes: 53 additions & 0 deletions doc/SecurityScan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# MobSF Security scan integration

## stage-security-scan.yml

This YAML configuration snippet outlines the setup for conditional security scanning within a CI/CD pipeline, specifically targeting iOS and Android platforms. The security scans are facilitated through the Mobile Security Framework (MobSF), a comprehensive tool designed for mobile security testing.

## Configuration Parameters
- **applicationEnvironment:** Specifies the deployment environment of the application. This string parameter helps in distinguishing artifacts by appending the environment name to the artifact's name.

- **enableIosSecurityScan:** A boolean parameter that, when set to true, enables security scanning for iOS applications.

- **enableAndroidSecurityScan:** Similar to enableIosSecurityScan, this boolean parameter enables security scanning for Android applications when set to true.

## Jobs Description
### iOS Security Scan Job (*OnLinux_iOS_SecurityScan*)
This job is designed to perform security scans on iOS applications. It is conditionally executed based on the `enableIosSecurityScan` parameter.

- **Condition for Execution:** The job runs if `enableIosSecurityScan` is set to true.
- **Execution Environment:** The job is executed on a Linux-based virtual machine, specified by the ubuntuHostedAgentImage variable.
- **Key Steps:**
- **Security Scan:** Utilizes a predefined template (`mobsf-scan.yml`) for conducting the security scan.
- **Parameters Passed:**
- `platform`: Specify the platform you'll be scanning.
- `fileExtension`: Required to specify the file extension MobSF will scan.
- `mobSfApiKey`: A key required for accessing MobSF services.
- `artifactName`: The name of the iOS artifact, appended with the specified applicationEnvironment.

### Android Security Scan Job (*OnLinux_Android_SecurityScan*)
This job mirrors the iOS security scan job but targets Android applications. It is also conditionally executed based on a specific parameter.

- **Condition for Execution:** The job runs if `enableAndroidSecurityScan` is set to true.
- **Execution Environment:** Similar to the iOS job, it runs on a Linux-based virtual machine specified by the ubuntuHostedAgentImage variable.
- **Key Steps:**
- **Security Scan:** Executes a predefined template (`mobsf-scan.yml`) for the Android security scan.
- **Parameters Passed:**
- `platform`: Specify the platform you'll be scanning.
- `fileExtension`: Specify the file extension MobSF will scan.
- `mobSfApiKey`: Required key for MobSF services.
- `artifactName`: The name of the Android artifact, appended with the specified applicationEnvironment.

## Usage
### How to Add the the new Stage for Security Scan

> 1. Create a new `stage`. (*stage: Security_Scan_Build_[Environment]*)
> 2. Configure the `dependsOn` property to the stage is creating the build, like `Build_Staging` and `Build_Production`.
> 3. Add the job we want to run using the new security template
> 4. Set the parameters `applicationEnvironment`, `enableIosSecurityScan`, `enableAndroidSecurityScan`
Integrating the security scanning configuration into your `azure-pipelines.yml` pipeline requires activating specific parameters to enable the process. Set `enableIosSecurityScan` and `enableAndroidSecurityScan` to **true** as per your project's requirements. This approach ensures a tailored security assessment for mobile applications across different environments, in this case Staging and Production, utilizing **MobSF** for comprehensive vulnerability detection prior to deployment.

## References
- [MobSF Documentation](https://mobsf.github.io/docs/#/)
- [MobSF API Docs](https://mobsf.live/api_docs)
5 changes: 4 additions & 1 deletion src/cli/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
# Changelog
# Changelog
All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)

Prefix your items with `(Template)` if the change is about the template and not the resulting application.

## 0.20.0
- Configured MobSF security scan on Android and iOS for Staging and Production builds.

## 0.19.4
- Fix CI/CD artifact name for iOS stage.

Expand Down

0 comments on commit b6ee09a

Please sign in to comment.