Solved

Best place to store program settings in the registry?

Posted on 2009-05-05
37
749 Views
Last Modified: 2012-05-06
I'm curious as to where is the best location in the registry to store settings for a VB.NET program. We are not using the "My.Settings" for this and do not want to. The program will run under an Admin account and will do quite a bit of disk IO(reading & writing.)

One place we found on-line suggested this location: HKEY_CURRENT_USER\Software\
Another this one: HKEY_LOCAL_MACHINE\Software\

What is the correct location?

Visual Studio 2008, Framework 3.5, Windows XP Pro

0
Comment
Question by:Stevejdl
  • 13
  • 12
  • 5
  • +2
37 Comments
 
LVL 33

Expert Comment

by:Todd Gerbert
ID: 24305823
If they're settings specific to the current user running the program, then put them in HKEY_CURRENT_USER\Software\CompanyName\ApplicationName.

If they're system-wide settings (i.e. applicable to every user running the program) put them in HKEY_LOCAL_MACHINE - however here you need admin privs to write settings (but not to read).
0
 
LVL 33

Expert Comment

by:Todd Gerbert
ID: 24305836
Each users' HKEY_CURRENT_USER is their own...i.e. if someone logs on, runs your program, changes a setting that's stored in HKCU, other users logging on won't see that setting change.
0
 
LVL 4

Expert Comment

by:Wardy_01
ID: 24305947
Neither, the registry is a mess and used for all sorts of horror stories.
Create a config file in the applications install folder and put the configuration in that.

Why would you need to use the registry anyway?
0
 
LVL 15

Expert Comment

by:oobayly
ID: 24306415
2nd Wardy_01's comment.
A settings file is the way to go. It's type safe so if you want to save a System.Drawing.Point object you don't have to convert it to a String and then back again. It will also cope with parsing errors better, ie:
User modified Settings file manualy, and saves 3000 in a Byte field, when the app loads the settings it will use the default value as 3000 isn't valid for Byte.

As for using HKLM, in Vista you may very well get a UAC prompt when attempting to edit values in that part of the registry.
0
 

Author Comment

by:Stevejdl
ID: 24306718
It's the sensitive material in the connection string and other info we trying to keep a user from getting at. The problem comes in that we encrypt the connection string, write that encrypted value to the registry, and then at some point we read the registry for the connection string to unencrypt. It's that pesky password needed to unencrypt that's the real headache. Since this password can't be given we, have to store it somewhere.  I hope that helps clarify the reason we don't want to have an ASCII config file laying around. Of course if a better way exist to store the password needed to unencrypt the conn string, we would more than willing to try it.
0
 
LVL 45

Expert Comment

by:aikimark
ID: 24308511
0
 

Author Comment

by:Stevejdl
ID: 24308923
We will be installing this product to many clients. I probably should have mentioned that it's not web based at all. What would really be ideal is if we could store the password encrypted in the registry or someplace else and modify it as needed. That's the real problem here. We thought the registry might be a decent to place to hide it, but that still leaves it open if someone ever got to the machine and found the location.
0
 

Author Comment

by:Stevejdl
ID: 24309303
I've looked over the links provided and with some modification the app.config file could be modified. I'm wondering though if these could be decrypted on the same machine with a .Net program.
0
 
LVL 15

Expert Comment

by:oobayly
ID: 24309385
Whilst you can hide the connectionstring from most users, a determined person who is familiar with .Net Reflector will be able to look at the source of you application. From that they will be able to determine how to decrypt any encrypted items in app.config, or where and how something is stored in the Registry.
0
 

Author Comment

by:Stevejdl
ID: 24310458
I was kind of wondering about that. So what is a solid way to ensure the password cannot be gotten to? How does outlook and others store the password? I mean somewhere there has to be a way to not ask the user for the decryption password. All this worrying about storing the password in a config file or the registry is for nothing if a determined user can get at it and decipher it. This might sound strange, but does nothing exist to password protect the password other than to enter it each time?
0
 
LVL 33

Expert Comment

by:Todd Gerbert
ID: 24311165
To answer your question: no, nothing can ever be done to protect your stored password 100%.

But, in reality, how many users of your application do you expect might even be remotely capable of de-compiling your application in order to learn the password, and even if they can do you expect they'd be willing to go through the trouble?
0
 
LVL 15

Expert Comment

by:oobayly
ID: 24312572
For apps like Outlook it's more difficult (but not impossible) to look at how they work. For .Net apps it's easier as they've been compiled into byte code.
As tgerbert said, it's nigh on impossible to protect your code 100%. One option would be to serialise your settings, encrypt them (using AES / Rijndael) and save them to disk. It'll hide your settings from all but the most determined people.

As for "do you expect they'd be willing to go through the trouble", it's a good point. I've opened up several 3rd party libraries in .Net Reflector, just out of curiosity. I'm sure I could remove the watermark out of a demo PDF creator (for example), but what's the point?

As your final product isn't web based, there should be no way of accessing another company's data, so there's no incentive to crack it, other than curiosity (but not maliciousness).

http://en.wikipedia.org/wiki/.NET_Framework#Architecture
http://en.wikipedia.org/wiki/.NET_Framework#Criticism
0
 
LVL 45

Expert Comment

by:aikimark
ID: 24313150
One approach would be to use one or more system-identifying data, along with some application-specific data as a key to decrypt a registry or config file.

If your application has access to a server in the enterprise, you might open a secured connection to the server and request the database userid/pwd combination.
0
 
LVL 15

Expert Comment

by:oobayly
ID: 24313621
I'd thought of the remote authentication approach too, but if you're still assuming that the user is capable of disassembling your application, then you'd have to assume that they can duplicate the request to the remote database and retrieve the credentials in a similar method to you app.

Using machine specific data is always possible, but often can be faked. Take an application that we license in our office. The licensing is done on per-user basis. Some of the people here work from home and need the s/w installed on a home pc (allowed as it's a per-user license, not a per-CPU licence). However the s/w provider refuses to provide us license keys for using it on a 2nd machine. I accidentally discovered that the machine specific key is generated from the UserName & Volume Serial of C:\. Solution: change the volume serial. We now can use the the software legally within it's licensing conditions and they can continue charging us 10,000 GBP per annum whilst treating us like criminals.
0
 
LVL 45

Expert Comment

by:aikimark
ID: 24314836
There are some third-party code-protection mechanisms that work with .Net.  I use Themida from (http://oreans.com/) on one of my Win32 applications and think that obfuscation is a very good technology.  You can combine the obfuscation with a non-.Net DLL to help protect you against crackers.
0
 
LVL 33

Expert Comment

by:Todd Gerbert
ID: 24315682
Here's an interesting article that seems to describe exactly what you're looking for.

http://weblogs.asp.net/jgalloway/archive/2008/04/13/encrypting-passwords-in-a-net-app-config-file.aspx
0
 
LVL 4

Expert Comment

by:Wardy_01
ID: 24373866
Probably a stupid question but ...

Why not have the code execute under the users own credentials, that way they already know the password so there's nothing to go looking for.

for things that are requiring secure connections to services that perhaps rely on a single account you could create a web service / server type application that the users client app talks to under their credentials.

This way you can use the power of a domin controller to ensure the user is who they say they are and you don't have to hide a copy of a sensitive connection string with username and password information all over your network because you are essentially "proxying access" to the database.

That's how I would do it anyway, but then I do work for the government so what would I know ... lol
0
 
LVL 45

Expert Comment

by:aikimark
ID: 24377085
@Wardy_01

You have to be careful not to expose your application to message replay and you would be limiting your applications to a single Windows domain.  If there was a man-in-the-middle attack on the application, the user name could be reused with other data or the same data to mess up the application or the spoofed user.  If this is a web-based application, you couldn't use Windows authentication at the database server.
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 

Author Comment

by:Stevejdl
ID: 24378887
It's a user based application that connects to an Oracle Database. It's an application that runs on the desktop and is used from many different offices. Some have domain servers and some don't. The connections are usually coming in to a centralized database.  The suggestion might work to have the domain control the passwords if the database was local to that site. Unfortunately it is not. I have gotten the app.config file to work but can't seem to find where the actual string is being stored. I look into the app.config file when the application is being complied but I don't see the string. If I exit the app and go back in, perform a decryption on the string it works. I just can't seem to find were the app is hiding the actual encrypted string. Is it by chance storing it under Documents and Settings\MyName\??? instead of where I'm running the application from? I searched in Documents and Settings but found no reference.
0
 
LVL 33

Expert Comment

by:Todd Gerbert
ID: 24378931
When it's compiled, if it's a application-scoped setting, it would have the same name as your application's EXE plus ".config" (e.g. MyApp.exe.config) and be in the same directory, in the case of a devel machine that'd be in your project's directory under Bin\Debug or Bin\Release.

User-scoped settings would be stored in a .config file under the users profile directory, in \Users\UserName\AppData on Vista or in \Documents and Settings\UserName\Local Settings in XP.
0
 

Author Comment

by:Stevejdl
ID: 24388201
Ok I found the encrypted section - thanks by the way. All looks good but a strange problem seems to exist when the program is closed while debugging. It happened while stepping through a section of code that had bug in it. After stopped the complier, and fixing the problem, I noticed the next time in the encrypted string from the config file was blank. After looking at the config file in the appSettings section, I noticed the encrypted section had been replaced by the standard appSettings section. The encrypted information had been wiped out. What happened? Will this problem appear again when the program is put back into production when or if an error occurs?
0
 
LVL 45

Expert Comment

by:aikimark
ID: 24388311
please post your code.  I suspect you copied/pasted a few statements too many.
0
 
LVL 33

Expert Comment

by:Todd Gerbert
ID: 24388742
Are you encrypting the entire settings section, or just your connection string?

0
 

Author Comment

by:Stevejdl
ID: 24388877
The entire section.
0
 

Author Comment

by:Stevejdl
ID: 24388885
If needed, give me a few and I'll post the code.
0
 

Author Comment

by:Stevejdl
ID: 24413120
I've added some try catch statements to the code to figure out the issue but they never get invoked.

Public NotInheritable Class EnString
    Private CurrentConnString As String
    Private m_SetAppPath As String
    Private m_SetConnStr As String
    Public Property SetAppPath() As String
        Get
            SetAppPath = m_SetAppPath
        End Get
        Set(ByVal value As String)
            m_SetAppPath = value
        End Set
    End Property
    Public Property SetConnStr() As String
        Get
            SetConnStr = m_SetConnStr
        End Get
        Set(ByVal value As String)
            m_SetConnStr = value
        End Set
    End Property
    Public Function GetConnectionString() As String
        CurrentConnString = String.Empty
        Try
            Dim config As Configuration = ConfigurationManager.OpenExeConfiguration(SetAppPath) 'System.Windows.Forms.Application.ExecutablePath)
            CurrentConnString = config.AppSettings.Settings("connectionString").Value.Trim().ToString()
        Catch ex As Exception
            Throw New Exception(ex.ToString)
        End Try
        Return CurrentConnString
    End Function
    Public Sub SetConnectionString()
        Try
            Dim config As Configuration = ConfigurationManager.OpenExeConfiguration(SetAppPath) 'System.Windows.Forms.Application.ExecutablePath)
            config.AppSettings.Settings("connectionString").Value = SetConnStr
            config.Save(ConfigurationSaveMode.Modified)
            ProtectSection("appSettings")
        Catch ex As Exception
            Throw New Exception(ex.ToString)
        End Try
    End Sub
    Private Sub ProtectSection(ByVal sSectionName As String)
        Dim config As Configuration = ConfigurationManager.OpenExeConfiguration(SetAppPath) 'ConfigurationUserLevel.None)
        Dim section As ConfigurationSection = config.GetSection(sSectionName)
        If section IsNot Nothing Then
            If Not section.IsReadOnly() Then
                Try
                    section.SectionInformation.ProtectSection("RsaProtectedConfigurationProvider")
                    section.SectionInformation.ForceSave = True
                    config.Save(ConfigurationSaveMode.Modified)
                Catch ce As ConfigurationException
                    Stop
                     Throw ce
                Catch se As SystemException
                    Stop
                    ' Throw se
                Catch ex As Exception
                    Stop
                    ' Throw ex
                End Try
            End If
        End If
    End Sub
End class    
0
 

Author Comment

by:Stevejdl
ID: 24425541
This post sounds interesting "One approach would be to use one or more system-identifying data, along with some application-specific data as a key to decrypt a registry or config file.'

How would one approach this idea?
0
 
LVL 33

Expert Comment

by:Todd Gerbert
ID: 24427907
Unless you're protecting nuclear launch codes, I think you may be going a little overboard! ;)

This article describes how to encrypt/decrypt a string of text (then you could store the encrypted string in the otherwise plain text config file).

http://weblogs.asp.net/jgalloway/archive/2008/04/13/encrypting-passwords-in-a-net-app-config-file.aspx

I'm not sure machine-specific stuff is the best solution, given that you need to provide the connection string at install time - which means you probably want it encrypted before you give it to the end-user, and thus before you know any machine-specific information about the install.
0
 

Author Comment

by:Stevejdl
ID: 24433431
I read that article before and was didn't go with the approach as it seemed to easy to decrypt the string. If I'm understanding it correctly, all you have to do is run the API again to decrypt it - no password needed. It didn't seem very secure at all. Maybe it's just my misunderstanding.
0
 
LVL 33

Expert Comment

by:Todd Gerbert
ID: 24433688
Yes, you can require a password. In the example in the article it's referred to as a "salt" or "entropy." This would be hard-coded into your application, and could be partially protected using a .Net obfuscation program - or using a native DLL to return it to the calling application.

You will NEVER be able to protect this information from EVERY possible attacker, no matter what mechanism you use someone will ALWAYS be able to break it. But, be realistic...what are the chances that your application is going to end up in the hands of someone both willing and able to go through the trouble of breaking a reasonable protection scheme?

If the data your customers will have access to is sensitive, perhaps you should re-think your database security; ideally it wouldn't matter if the end-user knows the connection string.
0
 
LVL 33

Expert Comment

by:Todd Gerbert
ID: 24433867
Actually, the ProtectedData class isn't going to work for you because that's machine-specific; if you encrypt the connection string on your development computer then you could only decrypt it on your dev system.

You'd need to use RijndaelManaged class instead, but same basic principal applies.
0
 

Author Comment

by:Stevejdl
ID: 24507567
We had Rijndael working from the beginning. It's the password to encrypt by that's been the real problem all along. Where to store it safely and how. We have came full circle to the problem of either storing it in the registry or a config file of some sort. I tried the config file concept but it is unreliable and can be decrypted rather easily. We wrote a small .net program to do just that. So I guess the registry is where it will have to end up. You know I keep coming back to that same old issue of how does Outlook and Microsoft programs store their passwords. Outlook does not require you to enter it each time the program starts. So how does Microsoft do it?
0
 
LVL 33

Expert Comment

by:Todd Gerbert
ID: 24530201
Outlook, Internet Explorer, etc., all store passwords that are originally provided by the user.  Therefore, their goal is to protect the password from unauthorized users; i.e. it doesn't matter if I'm able to discover the password Outlook has stored because I'm the one who provided it to Outlook in the first place.  Also, I suspect that you could easily discover these passwords with little effort, and maybe slightly more effort if you don't know the target users password.

You're talking about something entirely different, you need to give the user a piece of information that's sensitive - they should never know it. Therefore you want to encrypt it - but, as you pointed out, you also need to give the user's program a key otherwise they won't be able to de-crypt it for use.  But you don't want them to be able to *easily* learn the key (it's important to point out you can NEVER completely prevent them from learning the key), so where to hide it?  You need to give it to them in the first place somehow, e.g. in a .config file or as a property of an MSI - but either one of those would be easy to find.  I'd bury it in code, in an executeable.  I've attached a simple project that has a stored value in AppSettings that's encrypted - see if you can figure out what the secret is.

I'm not particularly familiar with C++ or the nitty gritty details of how code compiles, but I do know that I can de-compile a .Net assembly in a couple seconds but have zero idea how to even begin with native code; therefore, I've used a C++ DLL to provide the key to the .Net code.

I still think though that there's a better approach, i.e. re-designing database security such that it wouldn't matter if the user knew the SQL login.
0
 
LVL 33

Accepted Solution

by:
Todd Gerbert earned 500 total points
ID: 24530230
Guess you can't attach .MSI's...

http://12.164.78.32/EncryptedConfigExample.msi

0
 

Author Comment

by:Stevejdl
ID: 24604271
Thanks for the code. I haven't tried it yet. If time permits, I'll check it out sometime today.
0
 
LVL 33

Expert Comment

by:Todd Gerbert
ID: 24649427
Actually, that turned out to be quite easy to reverse engineer (the freebie .Net obfuscation tool didn't quite do as well as I had hoped)! ;)

But the basic idea still holds, and I think the techniques would probably work well in an actual project, as opposed to my two-line test program.
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

This article describes some techniques which will make your VBA or Visual Basic Classic code easier to understand and maintain, whether by you, your replacement, or another Experts-Exchange expert.
Entity Framework is a powerful tool to help you interact with the DataBase but still doesn't help much when we have a Stored Procedure that returns more than one resultset. The solution takes some of out-of-the-box thinking; read on!
Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…
This lesson covers basic error handling code in Microsoft Excel using VBA. This is the first lesson in a 3-part series that uses code to loop through an Excel spreadsheet in VBA and then fix errors, taking advantage of error handling code. This l…

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now