How do I avoid distributing sensitive information in my WiX / MSI by accident?
- I distributed a password, machine name or login credentials by accident with my MSI file. How do I best deal with this problem?
- After deployment my application connects erronously to my QA / UAT systems instead of my production systems - because of a faulty debugging construct in my setup's custom action code. How can I detect and avoid this?
- How do I avoid distribution such information in general?
This is a Q/A-style question with the simplest possible approach to avoid spreading sensitive information via your MSI by accident
All of this is obvious - if this has happened to you and you have sensitive information in the wild: all you can do is pull back the MSI (from download hopefully - it was even worse in the days of optical media), change any passwords or whatever else was revealed - and then make sure you don't experience it again. Now for the important part, how to avoid it for the future.
In addition to the information below on sensitive information, please also remember that some files you want to include in your setup may not be redistributable legally. Typical examples would be debugging tools from Microsoft or debugging tools from third party SDK toolkit. Please read documentation thoroughly and avoid use of such "hacky tools" in your custom actions.
Short Version
UPDATE: Let me jot down, before I forget, that you should eliminate the "downloaded file blocking flag" from all setup files (and generally read-only flags too).
All that is being suggested below is essentially to 1) scan your finalized MSI with Orca, 2) look over installed settings files as well as any template installation scripts delivered with your MSI. Further, 3) review your compiled custom action sources very well and maybe improve release build configuration practice (
#ifdef _DEBUG
for example, see below). 4) review your script custom actions by checking what is actually in your MSI (extract them). And crucially: to 5) get some help from other people for all manual testing - get some accomplices :-). Seriously: the setup is as important as the application - to make your solution succeed, it is your duty to get QA-personnel and other people involved testing - and also to tell them what and how to test.I would avoid trying to automate such checking yourself. There is no substitute for real eyeballs on the data. Perhaps a community solution would help long term. It could become part of a validation suite? Semi-automatic help might work, but fully auto-magic: forget it. There are too many ways to use all the rope you've got to shoot yourself in the foot.
Sensitive data may be the wrong term, maybe "invalid content" is more appropriate. Problems can result by your application pointing to your test server rather than production server on launch. Unexpected message boxes may pop up from custom actions (sometimes revealing sensitive data), and similar release blunders beyond pure sensitive data being exposed.
QA - Bug Quest
Checking for sensitive data included by accident obviously ties into general QA of your package. It should be done simultaneously with general testing. QA people are so busy with application testing that you really have to push this deployment testing, and make a test plan. Nothing fancy, but do test all installation modes (
install
,reinstall
,repair
,self-repair
,upgrade
,patching
,uninstall
,administrative install
and you should also dopublishing
andadvertisement
- if you have the setup to test this) and test all custom action functionality (thoroughly). Realistically and minimally you must test install, reinstall, uninstall and upgrade, but please test all modes.And if you are localizing, test in all core regions in all editions. Also run English in German locations, and vice versa just for smoke testing. In fact, test English in all regions - obvious I guess. Custom actions could easily fail on localized machines triggered by a random state on that machine (CA trying to access a hard coded English path for example and an exception results), or show some forgotten message box in English inside your exception handler code or similar that was never triggered on an English box.
And I guess I should mention the words of an experienced developer: "...don't hit too many people with testing until every bug found is a genuine surprise". And also - his funnier advice - for pre-releases leave in a couple of known bugs and tell the QA guys that there are such and such number of bugs to find - just for some motivation to focus the mind :-). P.S: I like to refer to this experienced developer as "The Elder Grasshopper", or as he is more commonly known "Veggie Boy". Confucius says: "Never trust a man who can be bribed with (organic) carrots!"
A large digression, back to the real topic: erroneous inclusion of sensitive data.
Checking MSI Files
I keep it simple when it comes to checking my MSI files for sensitive information.
How to check? Some scripted checks could be useful, but from experience I don't get fancy about it. I prefer a second pair of eyes over fancy script checking if I am honest. Just my two cents from real release work.
Registry
,Property
,IniFile
- but there could be something in several other locations.tables relating to GUI
are also vulnerable.ListBox
,ComboBox
,UIText
,Dialog
CustomAction
table orBinary
table - the latter requiring you to stream out any scripts - or check them in their source locations).msiexec.exe /a "Your.msi"
, orsetup.exe /a
(Installshield), orsetup.exe /extract
(Advanced Installer). Some setup.exe info.#ifdef _DEBUG
to wrapdebugging message boxes
and anyhard coded test variables
. See C++ snippet below. This means no experimental values are ever in release builds at all (the pre-processor will remove all debugging constructs).NOMB
to your release build as well? See sample below as well - should prevent stray release build message boxes - the define essentially "forbids" them (other, possible defines: How to tame the Windows headers (useful defines)?).user32.dll
), and it seems it even supports the aboveNOMB
feature as well as timeout. In other words you can set the message box both forbidden in release builds and to time-out in debug builds. Not tested thoroughly.d
to the file name for your compiled custom action dll - or any other file for that matter? Even if it causes you some extra work?Debug only message box in C++ custom action:
I use message boxes in order to attach the debugger to C++ custom action code. How to avoid these critters showing up in a release build? Here is one suggestion:
Advanced C++ guys will immediately see that they should make themselves a better macro for this - wrapping it all - I am no C++ wiz, so I'll leave that out for now (SafeMessageBox? DeploymentMessageBox?).
In
stdafx.h
, maybe additionally enableNOMB
(should preventMessageBox
from compiling unless wrapped with#ifdef _DEBUG
- makingMessageBoxes
only available in debug builds):(a fair bet this may become one of your most hated defines ever :-). Who smells a commented out section? I wouldn't use
#undef
to add an ad-hoc release message box - it ruins the whole protection feature - likely causing precisely what you hope to avoid: a stray message box. Perhaps just comment out the #define instdafx.h
if you have to, and enable the define again - automatically via the build process - for a real, public release build triggering a compile error for any stray message boxes)And as mentioned above, you could try the new MessageBoxTimeout method (from
user32.dll
, apparently available since XP) to show message boxes that don't get "stuck" but timeout after a specified number of seconds.Some context: #ifdef DEBUG versus #if DEBUG. People who actually know C++ properly, feel free to clarify or elaborate as required. The above is from a very old C++ project.
That is basically it - hardly rocket science - just "trifles that bite". Some further discussion on the topic below, but there is no substitute for this manual scanning IMHO. My honest suggestion, grab some people (managers are just fine :-) - pull them in as accomplices!), install Orca for them and just tell them to click through the tables and look in all settings files - and get a developer to help with the compiled custom action code. Just looking at the raw Orca tables may even be effective in order to find other bugs or imperfections as well.
Sensitive Information
There is plenty of opportunity to include sensitive information in your MSI sources by accident during development:
login credentials
,passwords
,database connection strings
,user names
,share name
,IP-address
,machine names
,ftp passwords
,web host login credentials
orother sensitive data
.Your MSI should obviously not contain any such sensitive information at all - unless you want to point to your own web-site of course, or provide a contact email or telephone number. However, anything else is almost always undesirable - and it is quick to forget to remove such hard coded information from production MSI-files due to development experimentation (often in script custom actions - or compiled custom actions for that matter - even worse and not detectable by the Orca review approach suggested above, but generally not view-able by the user unless it is show via an unexpected message box - or if .NET managed code is disassembled).
If actually required for the install, such "sensitive" information should be parameters (properties) that are set by the end user at install time, either via the setup's interactive GUI or set via PUBLIC PROPERTIES or transforms at the command line when the setup is being installed. There is some information here on using transforms and PUBLIC PROPERTIES: How to make better use of MSI files for silent, corporate deployment of MSI files (the linked answer also provides a rather ad-hoc description of MSI problems and benefits in a more general sense).