Skip to content

Add VPN and Developer mode detection #65

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
May 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
# freeRASP 3.8.0

- ⚡ Added new threat `systemVPN` for VPN detection
- 📄 Documentation updates

### Android

- ⚡ Added new threat `devMode` for Developer mode detection
- ⚡ Enhanced and accelerated the data collection logic
- ⚡ Fixed proguard warning in specific versions of RN
- ⚡ Fixed issue with Arabic alphabet in logs caused by the device’s default system locale
- ✔️ Increased the version of the GMS dependency
- ✔️ Updated CA bundle

### iOS
- ⚡ Fixed issue with Arabic alphabet in logs caused by the device’s default system locale
- ⚡ Passcode check is now periodical
- ✔️ Updated CA bundle

# freeRASP 3.7.2

- ⚡ Update expo config plugin to fix release build issue in RN 0.73
Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,10 @@ const actions = {
console.log('secureHardwareNotAvailable');
},
// Android & iOS
systemVPN: () => {
console.log('systemVPN');
},
// Android & iOS
passcode: () => {
console.log('passcode');
},
Expand All @@ -233,6 +237,10 @@ const actions = {
obfuscationIssues: () => {
console.log('obfuscationIssues');
},
// Android only
devMode: () => {
console.log('devMode');
},
};

useFreeRasp(config, actions);
Expand Down Expand Up @@ -507,6 +515,8 @@ freeRASP is freemium software i.e. there is a Fair Usage Policy (FUP) that impos
<li>Screen lock control</li>
<li>Google Play Services enabled/disabled</li>
<li>Last security patch update</li>
<li>System VPN control</li>
<li>Developer mode control</li>
</ul>
</td>
<td>yes</td>
Expand Down
3 changes: 2 additions & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ android {
buildTypes {
release {
minifyEnabled true
proguardFiles "proguard-rules.pro"
}
}

Expand Down Expand Up @@ -86,7 +87,7 @@ dependencies {
//noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:$react_native_version"
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "com.aheaditec.talsec.security:TalsecSecurity-Community-ReactNative:9.1.0"
implementation "com.aheaditec.talsec.security:TalsecSecurity-Community-ReactNative:9.6.0"
}

if (isNewArchitectureEnabled()) {
Expand Down
1 change: 1 addition & 0 deletions android/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-dontwarn java.lang.invoke.StringConcatFactory
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ internal object FreeraspThreatHandler : ThreatListener.ThreatDetected, ThreatLis
listener?.threatDetected(Threat.SecureHardwareNotAvailable)
}

override fun onDeveloperModeDetected() {
listener?.threatDetected(Threat.DevMode)
}

override fun onSystemVPNDetected() {
listener?.threatDetected(Threat.SystemVPN)
}

internal interface TalsecReactNative {
fun threatDetected(threatType: Threat)
}
Expand Down
7 changes: 5 additions & 2 deletions android/src/main/java/com/freeraspreactnative/Threat.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ internal sealed class Threat(val value: Int) {
object DeviceBinding : Threat((10000..999999999).random())
object UnofficialStore : Threat((10000..999999999).random())
object ObfuscationIssues : Threat((10000..999999999).random())
object SystemVPN : Threat((10000..999999999).random())
object DevMode : Threat((10000..999999999).random())

companion object {
internal fun getThreatValues(): WritableArray {
Expand All @@ -33,12 +35,13 @@ internal sealed class Threat(val value: Int) {
Passcode.value,
Simulator.value,
SecureHardwareNotAvailable.value,
SystemVPN.value,
DeviceBinding.value,
UnofficialStore.value,
ObfuscationIssues.value
ObfuscationIssues.value,
DevMode.value
)
)

}
}
}
18 changes: 18 additions & 0 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,14 @@ const App = () => {
);
},
// Android & iOS
systemVPN: () => {
setAppChecks((currentState) =>
currentState.map((threat) =>
threat.name === 'System VPN' ? { ...threat, status: 'nok' } : threat
)
);
},
// Android & iOS
passcode: () => {
setAppChecks((currentState) =>
currentState.map((threat) =>
Expand All @@ -126,6 +134,16 @@ const App = () => {
)
);
},
// Android only
devMode: () => {
setAppChecks((currentState) =>
currentState.map((threat) =>
threat.name === 'Developer Mode'
? { ...threat, status: 'nok' }
: threat
)
);
},
};

useFreeRasp(config, actions);
Expand Down
16 changes: 10 additions & 6 deletions example/src/checks.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
export const commonChecks = [
{ name: 'App Integrity', status: 'ok' },
{ name: 'Privileged Access', status: 'ok' },
{ name: 'Debug', status: 'ok' },
{ name: 'Simulator', status: 'ok' },
{ name: 'App Integrity', status: 'ok' },
{ name: 'Unofficial Store', status: 'ok' },
{ name: 'Hooks', status: 'ok' },
{ name: 'Device Binding', status: 'ok' },
{ name: 'Secure Hardware Not Available', status: 'ok' },
{ name: 'Passcode', status: 'ok' },
{ name: 'Simulator', status: 'ok' },
{ name: 'Secure Hardware Not Available', status: 'ok' },
{ name: 'System VPN', status: 'ok' },
{ name: 'Device Binding', status: 'ok' },
{ name: 'Unofficial Store', status: 'ok' },
];

export const iosChecks = [{ name: 'Device ID', status: 'ok' }];

export const androidChecks = [{ name: 'Obfuscation Issues', status: 'ok' }];
export const androidChecks = [
{ name: 'Obfuscation Issues', status: 'ok' },
{ name: 'Developer Mode', status: 'ok' },
];
41 changes: 23 additions & 18 deletions ios/FreeraspReactNative.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ import TalsecRuntime
class FreeraspReactNative: RCTEventEmitter {

public static var shared:FreeraspReactNative?

let threatChannelKey = String(Int.random(in: 100_000..<999_999_999)) // key of the argument map under which threats are expected
let threatChannelName = String(Int.random(in: 100_000..<999_999_999)) // name of the channel over which threat callbacks are sent
let threatIdentifierList = (1...12).map { _ in Int.random(in: 100_000..<999_999_999) }

override init() {
super.init()
Expand Down Expand Up @@ -45,27 +44,27 @@ class FreeraspReactNative: RCTEventEmitter {
let config = TalsecConfig(appBundleIds: [appBundleIds], appTeamId: appTeamId, watcherMailAddress: watcherMailAddress, isProd: isProd)
Talsec.start(config: config)
}

/**
* Method to setup the message passing between native and React Native
*/
@objc(getThreatChannelData:withRejecter:)
private func getThreatChannelData(resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) -> Void {
resolve([threatChannelName, threatChannelKey])
}

func dispatchEvent(securityThreat: SecurityThreat) -> Void {
FreeraspReactNative.shared!.sendEvent(withName: threatChannelName, body: [threatChannelKey: securityThreat.callbackIdentifier])
}

/**
* Method to get the random identifiers of callbacks
*/
@objc(getThreatIdentifiers:withRejecter:)
private func getThreatIdentifiers(resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) -> Void {
resolve(getThreatIdentifiers())
}

/**
* We never send an invalid callback over our channel.
* Therefore, if this happens, we want to kill the app.
Expand All @@ -74,7 +73,7 @@ class FreeraspReactNative: RCTEventEmitter {
private func onInvalidCallback() -> Void {
abort()
}

private func getThreatIdentifiers() -> [Int] {
return SecurityThreat.allCases
.filter {
Expand All @@ -90,33 +89,39 @@ class FreeraspReactNative: RCTEventEmitter {
}
}

struct ThreatIdentifiers {
static let threatIdentifierList: [Int] = (1...12).map { _ in Int.random(in: 100_000..<999_999_999) }
}

/// An extension to unify callback names with RN ones.
extension SecurityThreat {

var callbackIdentifier: Int {
switch self {
case .signature:
return FreeraspReactNative.shared!.threatIdentifierList[0]
return ThreatIdentifiers.threatIdentifierList[0]
case .jailbreak:
return FreeraspReactNative.shared!.threatIdentifierList[1]
return ThreatIdentifiers.threatIdentifierList[1]
case .debugger:
return FreeraspReactNative.shared!.threatIdentifierList[2]
return ThreatIdentifiers.threatIdentifierList[2]
case .runtimeManipulation:
return FreeraspReactNative.shared!.threatIdentifierList[3]
return ThreatIdentifiers.threatIdentifierList[3]
case .passcode:
return FreeraspReactNative.shared!.threatIdentifierList[4]
return ThreatIdentifiers.threatIdentifierList[4]
case .passcodeChange:
return FreeraspReactNative.shared!.threatIdentifierList[5]
return ThreatIdentifiers.threatIdentifierList[5]
case .simulator:
return FreeraspReactNative.shared!.threatIdentifierList[6]
return ThreatIdentifiers.threatIdentifierList[6]
case .missingSecureEnclave:
return FreeraspReactNative.shared!.threatIdentifierList[7]
return ThreatIdentifiers.threatIdentifierList[7]
case .systemVPN:
return ThreatIdentifiers.threatIdentifierList[8]
case .deviceChange:
return FreeraspReactNative.shared!.threatIdentifierList[8]
return ThreatIdentifiers.threatIdentifierList[9]
case .deviceID:
return FreeraspReactNative.shared!.threatIdentifierList[9]
return ThreatIdentifiers.threatIdentifierList[10]
case .unofficialStore:
return FreeraspReactNative.shared!.threatIdentifierList[10]
return ThreatIdentifiers.threatIdentifierList[11]
@unknown default:
abort()
}
Expand Down
10 changes: 5 additions & 5 deletions ios/TalsecRuntime.xcframework/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,30 @@
<array>
<dict>
<key>LibraryIdentifier</key>
<string>ios-arm64_x86_64-simulator</string>
<string>ios-arm64</string>
<key>LibraryPath</key>
<string>TalsecRuntime.framework</string>
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
<string>x86_64</string>
</array>
<key>SupportedPlatform</key>
<string>ios</string>
<key>SupportedPlatformVariant</key>
<string>simulator</string>
</dict>
<dict>
<key>LibraryIdentifier</key>
<string>ios-arm64</string>
<string>ios-arm64_x86_64-simulator</string>
<key>LibraryPath</key>
<string>TalsecRuntime.framework</string>
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
<string>x86_64</string>
</array>
<key>SupportedPlatform</key>
<string>ios</string>
<key>SupportedPlatformVariant</key>
<string>simulator</string>
</dict>
</array>
<key>CFBundlePackageType</key>
Expand Down
Binary file modified ios/TalsecRuntime.xcframework/_CodeSignature/CodeDirectory
Binary file not shown.
Binary file modified ios/TalsecRuntime.xcframework/_CodeSignature/CodeRequirements-1
Binary file not shown.
Loading
Loading