Avoid Native Calls
ID |
kotlin.avoid_native_calls |
Severity |
high |
Resource |
Api |
Language |
Kotlin |
Tags |
CWE:246, NIST.SP.800-53, PCI-DSS:6.5.6 |
Rationale
Calling native code from Kotlin can introduce significant security risks and maintenance challenges.
Native methods can compromise Kotlin’s platform independence and the built-in security mechanisms that the Java Virtual Machine (JVM) offers, such as memory safety and automatic garbage collection. Moreover, improper implementation of JNI can lead to vulnerabilities like buffer overflows, null pointer dereferences, and arbitrary code execution alongside difficulties in debugging and higher maintenance overhead due to varying behavior on different operating systems.
class NativeExample {
// Declaration of a native method
external fun nativeMethod() // FLAW
companion object {
init {
// Load native library
System.loadLibrary("NativeLib")
}
@JvmStatic
fun main(args: Array<String>) {
NativeExample().nativeMethod()
}
}
}
Using such methods inadvertently creates attack vectors that can be exploited by malicious actors. Generally, it is advisable to minimize JNI usage and look for pure Kotlin alternatives wherever feasible. JNI should only be used in scenarios where no other alternatives are available, and even then, it should be approached cautiously with strict security controls in place.
Remediation
To remediate the security risks associated with native method calls, consider the following best practices:
-
Evaluate the Necessity: First, ascertain if the JNI invocation is absolutely necessary. Examine whether a Kotlin equivalent exists that fulfills the same requirement without resorting to platform-specific code.
-
Kotlin Libraries and APIs: Leverage Kotlin’s extensive range of built-in libraries and APIs, which often offer superior safety and portability compared to custom native code, avoiding the need to handle low-level system operations directly.
-
Security Controls: If JNI must be used, implement rigorous security controls:
-
Validate all inputs diligently before passing them to native code to mitigate risks of buffer overflows or injections.
-
Encapsulate native calls within well-defined interfaces and limit their exposure to other parts of the application to minimize the attack surface.
-
-
Code Reviews and Testing: Conduct thorough code reviews and extensive testing, particularly focusing on edge cases around data bounds and error handling to ensure robustness and safety of native interactions.
By following these remediation steps, applications can maintain their security posture and robustness while minimizing the risks associated with platform-specific native calls.