简体   繁体   中英

c# emailing using static method in separate class

I have a small program that checks a few folders for old files and if it finds them, it sends an email to me. Everything works, but I have my email username and password hard coded in as:

SmtpServer.Credentials = new System.Net.NetworkCredential(
    "uname@domain.com", "password");

A friend looked at it and mentioned that he would use a separate class to be able to reuse the email code using a static method but I'm not sure if that will help (or how to implement that). I'm going to start using Git/GitHub for change tracking and I don't want to have my email hard coded into a public repository.

I know the smtp password needs to be in plain text somewhere to work, but can I hide that outside my code and call it with a 'using' or some other option so the password isn't stored in the code?

Program written using Visual Studio Express 2012

Edit 1: Should have said this is just a console application .exe file that is called by a Windows Scheduled Task to do some folder monitoring on a remote server. So it's compiled on my pc, but the exe file is saved and scheduled to run remotely.

For things like credentials (usernames and passwords) it's generally best to treat them as environmental configuration details. That is, for any given instance of the application operating in any given environment, it would need a handful of configurable values to interact with the mail server:

  • Hostname
  • Username
  • Password

Environmental configuration generally goes in the App.config or Web.config file. At its simplest, you might have something like this in the config file:

<appSettings>
  <add key="SMTPUsername" value="uname@domain.com" />
  <add key="SMTPPassword" value="password" />
</appSettings>

Then to pull them from the configuration in your code, you'd do something like this:

SmtpServer.Credentials = new System.Net.NetworkCredential(
    System.Configuration.ConfigurationManager.AppSettings["SMTPUsername"],
    System.Configuration.ConfigurationManager.AppSettings["SMTPPassword"]);

You can abstract those settings behind a custom configuration class, have in-code defaults in case of empty values in the configuration, do all sorts of error checking on the configuration values, etc. But ultimately you're pulling the values from the config file.

The config file can then be kept separate from your publicly-visible source code. You'd want a config file included in the source code which contains sample configuration data, so people consuming the project can now how to configure it. But you can keep a not-checked-in local configuration for your own needs, and deploy a custom configuration file to any production server which runs this application. (That's really what configuration files are for, storing values which differ between instances of the same application.)

Whether you create a static helper method to handle this isn't really relevant to hiding these values. You certainly can create such a method. It doesn't need to be static, if you'd prefer a mailer object which you'd instantiate. (Maybe something which implements IDisposable and uses that to internally dispose of SMTP object resources? Get as creative as you want, really.) But that abstraction alone doesn't hide your values, it just moves them from one class in the source code to another. You want to remove them from the source code entirely.

Moving this into another DLL will not help in hiding this information, to do that, a very simple (yet basic) way to protect it is to first move this to your user info to your app config like

<appSettings>
  <add key="user" value="user@mydomain.com" />
  <add key="pwd" value="some password" />
</appSettings>

Next you need to encrypt that section, if it's a web app you can just run the below and it will do the work for you

aspnet_regiis -pe "WebConfigSectionName" -app "/WebAppName"

If your app is not a web app then you still can encrypt it, but you will need to write your own encryption routine, see this MSDN article

Finally in your code, you should be able to read the data from the config, note that it's been some time since I last did this, so experiment a bit, but I don't think you need anything special to read it in

string user = ConfigurationManager.AppSettings["user"];
string pwd = ConfigurationManager.AppSettings["pwd"];

Caveat: If I recall correctly, the user context under which you run the encryption and your app must be the same or have access to the same key, meaning, if you run the app (or aspnet_regiis) to encrypt the app config section as "MySecurityUser", then the account running the app when it needs to read the encrypted section must be "MySecurityUser", it can't be "DaveUserId" (you won't be able to decrypt it)

can I hide that outside my code and call it with a 'using' or some other option so the password isn't stored in the code?

Sure, store the information in a configuration file somewhere. Read in the file programmatically. The issue here is of course that a separate config file is, in many cases, more exposed than in compiled code.

You can encrypt the information, and then only store the encrypted version in the config file, but then either your config file, or somewhere else in your program, you need to store the private key to decrypt the password. You've now essentially begged the question, as you now need to know where to safely store the private key. This makes this problem effectively unsolvable. You can make some information a bit harder to find by burying it deeply, or requiring someone to jump through a lot of hoops to get to it, but if there's some way for the program to get some sensitive information, and you have an intelligent, determined, malicious person with access to that program, then they will eventually be able to get to it.

Im sure there are a lot of solutions for this, but one thing you could do is store your email credentials in your app.config, and access them like this:

string email = ConfigurationManager.AppSettings["Email"];
string password = ConfigurationManager.AppSettings["Password"];

Have you tried adding the values to your application settings?

You can access the settings from your the Project menu, look for " Properties...". That will open the properties page and on the left you'll see "Settings". Fill in your setting name (for example "Password") and type (likely string). The value will be persisted in an xml file named "app.config" in your project. Once compiled, you'll see the that file as ".exe.config". You can modify that config file when you've deployed.

Access that value by name in your code:

SmtpServer.Credentials = new System.Net.NetworkCredential(
    "uname@domain.com", Properties.Settings.Default.Password);

This way you can modify the setting without committing confidential info to a repository somewhere.

Is asking them to enter their own email information a possiblity?

One option is to put it in the registry:

http://www.codeproject.com/Articles/3389/Read-write-and-delete-from-registry-with-C

another option is to use web.debug.config and don't include in the repository:

How can I use Web.debug.config in the built-in visual studio debugger server?

If you will run your application at the same PC you can use ProtectedData.

So first encrypt your user name and password(ie in debug mode, save it and then use encypted string in .cs file).

SmtpServer.Credentials = new System.Net.NetworkCredential( ProtectedData.Unprotect([encrypted]), ProtectedData.Unprotect([here encrypted data]));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM