DEV Community

Cover image for Your .NET Secrets Are In Your Strings (Here’s How to Stop Them)
Skater
Skater

Posted on

Your .NET Secrets Are In Your Strings (Here’s How to Stop Them)

If you’ve ever shipped a .NET .dll or .exe and worried about API keys, connection strings, or license endpoints being discoverable-good instinct. But here’s the part many teams miss:
In .NET, string literals are trivially searchable.
Open the assembly in ILSpy/dnSpy/dotPeek, hit search, and you can instantly surface things like:
• https://api.yourcompany.com/...
• Server=prod-sql01;User Id=...;Password=...
• license validation URLs
• error messages that reveal internal logic
Even worse: once an attacker finds one valuable string, it becomes a breadcrumb for finding the surrounding code.
So what do you do? You remove the “easy first foothold” by making sensitive strings not appear as plaintext in the managed assembly.
The two-tier protection model: encrypt in managed code or move secrets native
To hide sensitive string literals in a .NET assembly, you generally have two escalating approaches:
1) In-assembly encryption (easy deployment, good general protection)
Your strings remain inside the managed binary-but are replaced with encrypted ciphertext. At runtime, the app decrypts them when needed.
What you gain
• Strings stop being readable in decompilers.
• You don’t introduce extra binaries.
What you don’t fully get
• The decryption routine still exists in managed IL.
• The secrets will still appear in memory during runtime.
Use this when the risk is “people poking at strings,” and you want strong mitigation with minimal operational friction.
2) Native DLL storage (strongest against static decompilation)
Instead of keeping secrets in the managed assembly at all, you extract selected strings from the .NET binary and place them into a compiled native (C++) DLL.
Then the .NET app retrieves the values at runtime through P/Invoke.
What you gain
• The sensitive strings are completely absent from the managed assembly.
• Standard .NET decompilers won’t show them because they’re not in IL.
Trade-off
• You must ship the native DLL alongside your app.
• If the native DLL is missing, the app should fail fast (e.g., DllNotFoundException)-there’s no “fallback” because the secrets aren’t in the managed assembly anymore.
Practical selection: which strings deserve which protection?
Not all strings carry the same impact. A sensible approach is:
• Native DLL storage for:
o API keys and tokens
o database connection strings (credentials included)
o license server endpoints
o cryptographic salts / high-value secrets
• In-assembly encryption for:
o error messages
o UI text
o lower-sensitivity strings
o anything that would reveal structure but not directly compromise credentials
How to validate you got it right
After obfuscation:

  1. Confirm the strings aren’t recoverable via decompiler search o With in-assembly encryption: you should see unreadable encoded/ciphertext representations. o With native DLL storage: the exact plaintext should show zero results in the managed assembly.
  2. Run functional tests o Exercise code paths that depend on those secrets. o Verify API calls, DB connections, and license flows still work normally.
  3. If you used native DLL storage, verify deployment o Ensure the native DLL is present next to the executable. o Confirm your installer/build pipeline includes it. Common pitfalls (and why they happen) • App fails with DllNotFoundException o The native DLL wasn’t shipped correctly. • Strings are still visible o You didn’t select them for protection, or a “minimum length” threshold excluded them. • Slowdowns o Encrypting too many strings, especially those in performance-hot paths. o Encrypt selectively-protect secrets, not everything. Bottom line If your goal is to prevent “open ILSpy and search” from exposing your secrets, string encryption is the baseline, and native DLL storage is the strongest option. If the string would cause serious harm when leaked, treat it like a secret-not like harmless text. ________________________________________

Top comments (0)