I've got some sensitive data (api secret key) to store in the app on the client-side, I know this is a bad practice to store this kind of information but there are not feasible alternatives for now, I'm already tampering the problems that could arise if such key is leaked, but I wish to know if encoding such key in the build during compile time is secure or not, in case of decompiling the code, even if obfuscated, is it more difficult to retrive a compile-time variable?

Here an example of how I would use it

flutter build apk --dart-define=APP_VERSION=0.1.2 --dart-define=SECRET_KEY=123456


Solution 1: Rob Napier

This is precisely as insecure as any other approach.

Create project that uses the define

(If the define isn't used, it'll be stripped out, but obviously you want to use it.)

void main() {
  const String key = String.fromEnvironment('SECRET_KEY');
  print(key);
  runApp(const MyApp());
}

Build

I'm using "SEKRET" here rather than "123456" because there are a lot of "123456" strings in a normal APK and it could give a false positive.

flutter build apk --dart-define=APP_VERSION=0.1.2 --dart-define=SECRET_KEY=SEKRET

Open the APK

cd build/app/outputs/flutter-apk/
mkdir app
cd app
unzip ../app-release.apk

Look for secret strings

strings lib/x86_64/libapp.so | grep SEKRET
> SEKRET

This is no different than just hardcoding the string into the app. There is no benefit to "hiding" it in a define, and there's no way to really secure this. The best you can do is obfuscate and hope the attacker isn't highly motivated. Or invest in ongoing obfuscation and hardening improvements every time they crack your system. (This is very difficult and expensive, and there is, by its nature, no universal or permenant solution.)

You cannot hide an API key in a binary. You cannot hide an API key that an app uses in memory. You cannot reliably keep secrets from someone who controls the hardware the app runs on and is motivated to find those secrets.