Encrypting a connection string in memory using a class - c#

I am writing a Windows Service using C# and .Net 4.6. The service is configured such that it runs perpetually by sleeping for a configurable period of time, before running and performing some tasks. As part of the initial start-up, the service goes and gets a list of connection strings so it can connect to a list of database servers and gather some information. I want to be able to persist the connection strings in memory. The idea is that the service grabs the connection strings on startup and holds them in memory until the service stops. Next time it starts it goes and grabs them again. This has led me down the path of encrypting the connection strings as some may contain username/password combinations.
So What I have tried to do it create a class to store this information, and handle the encryption/decryption of the connection string on the fly with the get and set properties.
Note: I have hard-coded a length of the byte array to 1024, but this should probably be dynamically adjusted to the nearest 16.
using System;
using System.Text;
using System.Security.Cryptography;
namespace XXXXXXX.DB
{
public class Instance
{
private byte[] _connectionString = new byte[1024];
System.Text.ASCIIEncoding ae = new ASCIIEncoding();
public string Name { get; set; }
public string ConnectionString
{
set
{
if (value.Length < _connectionString.Length)
value = value.PadRight(_connectionString.Length, ' ');
else
value = value.Substring(0, _connectionString.Length);
_connectionString = ae.GetBytes(value);
ProtectedMemory.Protect(_connectionString, MemoryProtectionScope.SameProcess);
}
get
{
ProtectedMemory.Unprotect(_connectionString, MemoryProtectionScope.SameProcess);
return ae.GetString(_connectionString).Trim();
}
}
}
So I set the ConnectionString property on an Instance object and it is encrypted as I expect. But when I access the unencrypted ConnectionString, the result is still encrypted:
using (SqlConnection connection = new SqlConnection(_theInstance.ConnectionString))
I think this is the fact that the private member variable for ConnectionString is a byte array which is a reference type? To be honest I'm scratching my head a bit on this.
Please note I've looked at many, many examples that make a simple console app and do the encryption and unencrypted all in the same method - but can it be done as I'm trying to do?

Related

CredentialManagement returning empty strings in production but not development

I'm having an issue using the Windows credential manager in a project. I am using it to replace the username and password on the connectionString in my appsettings, and in the development and QA environments everything works fine, but in the production environment (which I don't have complete access to) it does not. The issue is its returning empty string when I load the credentials from the target.
Here is where I am loading it:
public static CredentialModel GetCredential(string target)
{
CredentialModel credentialDto = new CredentialModel();
using var credential = new Credential
{
Target = target
};
credential.Load();
credentialDto.UserName = credential.Username;
credentialDto.Password = credential.Password;
return credentialDto;
}
And this is the CredentialModel
public class CredentialModel
{
public string UserName { get; set; }
public string Password { get; set; }
}
And where I replace the credentials in the connectionString:
StringBuilder connectionString = new(host.Configuration.GetConnectionString("RemessasConnectionString"));
var credential = CredentialService.GetCredential("Pegasus");
connectionString.Replace("$userId", credential.UserName);
connectionString.Replace("$password", credential.Password);
ConnectionString = connectionString.ToString();
For debugging's sake I added a line to the log in order to see what was being added to the connectionString, and it is replacing it with an empty string in production, but the actual values in development.
I have one idea about the reason for this, the application is running with a windows user and that user does not have access to the windows credential manager in the production server (but I think this would return an error not just empty strings).
If anyone can point me in the right direction, or has any suggestions for me to try I am all ears.
As #richard-deeming pointed out, the its because the user running the application does not have access to the credentials stored since they were stored under a different account than the one running the service. Look at his comment for more detail.

How to decrypt/open (.db) SQLite database file

How to open a file with the .db extension of SQLite database?
I have downloaded a DB Browser For SQLite.
When I tried opening the database file, a new window popped up which is 'Titled SQLCipher Encryption' asking a password used to encrypt and file size (Confused With What Exactly 'File Size'..?).
I have an Application Source Code that I Managed To Find Password & tried with default Page Size 1024.
Tried Several times but unable to open.
public void ReadRecord(string sql)
{
try
{
this.sqlite_cmd.CommandText = this.cSql;
this.sqlite_datareader = this.sqlite_cmd.ExecuteReader();
if (this.sqlite_datareader.Read())
{
this.sAddEdit = "E";
this.txt1.Tag = this.sqlite_datareader["id"];
this.txt1.Text = this.sqlite_datareader["f0"].ToString();
this.txt2.Text = this.sqlite_datareader["f1"].ToString();
this.txt3.Text = this.sqlite_datareader["f2"].ToString();
this.txt4.Text = this.sqlite_datareader["f3"].ToString();
this.txt5.Text = this.sqlite_datareader["f4"].ToString();
this.dtpListDate.Text = this.sqlite_datareader["f5"].ToString();
this.txt7.Text = this.sqlite_datareader["f6"].ToString();
this.txt8.Text = this.sqlite_datareader["f7"].ToString();
this.txt9.Text = this.sqlite_datareader["f8"].ToString();
this.txt10.Text = this.sqlite_datareader["f9"].ToString();
this.txt11.Text = this.sqlite_datareader["f10"].ToString();
this.txt12.Text = this.sqlite_datareader["f11"].ToString();
this.txt13.Text = this.sqlite_datareader["f12"].ToString();
this.txt14.Text = this.sqlite_datareader["f13"].ToString();
this.txt15.Text = this.sqlite_datareader["f14"].ToString();
this.txt16.Text = this.sqlite_datareader["f15"].ToString();
this.txt17.Text = this.sqlite_datareader["f16"].ToString();
this.txt18.Text = this.sqlite_datareader["f17"].ToString();
this.txt19.Text = this.sqlite_datareader["f18"].ToString();
this.txt20.Text = this.sqlite_datareader["f19"].ToString();
this.txt21.Text = this.sqlite_datareader["f20"].ToString();
this.txt22.Text = this.sqlite_datareader["f21"].ToString();
this.txt23.Text = this.sqlite_datareader["f22"].ToString();
this.txt24.Text = this.sqlite_datareader["f23"].ToString();
this.txt25.Text = this.sqlite_datareader["f24"].ToString();
this.txt26.Text = this.sqlite_datareader["f25"].ToString();
this.txt27.Text = this.sqlite_datareader["f26"].ToString();
this.txt28.Text = this.sqlite_datareader["f27"].ToString();
this.txt29.Text = this.sqlite_datareader["f28"].ToString();
this.txt30.Text = this.sqlite_datareader["f29"].ToString();
}
this.sqlite_datareader.Close();
}
catch (Exception exception)
{
MessageBox.Show("A Error" + exception.ToString() + " Occcured Please Try Again or contact supplier", "Error", MessageBoxButtons.OK, MessageBoxIcon.Hand);
}
}
In namespace,
using Microsoft.VisualBasic.PowerPacks;
using System;
using System.ComponentModel;
using System.Data;
using System.Data.SQLite;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
1. regarding your question about page size,
please refer to SQLite Database file Format
1.3.2. Page Size
The two-byte value beginning at offset 16 determines the page size of the database. For SQLite versions 3.7.0.1 (2010-08-04) and earlier, this value is interpreted as a big-endian integer and must be a power of two between 512 and 32768, inclusive. Beginning with SQLite version 3.7.1 (2010-08-23), a page size of 65536 bytes is supported. The value 65536 will not fit in a two-byte integer, so to specify a 65536-byte page size, the value at offset 16 is 0x00 0x01. This value can be interpreted as a big-endian 1 and thought of as a magic number to represent the 65536 page size. Or one can view the two-byte field as a little endian number and say that it represents the page size divided by 256. These two interpretations of the page-size field are equivalent.
You can check the size of the database by using the ".dbinfo" command in an ordinary sqlite3.exe command-line shell program. The first info is the size
database page size: 4096
2. Regarding db decryption
Assuming the db is encrypted and you have the right passwords, (does it start with x' or 0x?, have you managed to open the db manually using the DB Browser app?), you'll have to decrypt the db before being able to read it. please refer SQLite Encryption Extension Documentation in order to learn more about the SQLite encryptions (& decryptions).
I suggest to use some opened source written cipher. just google it up and see which one is comfortable for you to work with. here's an example cipher that might be good for your needs

Remove WCF SOAP client request from memory

I have set up a little demo project to show my issue. I have a vanilla WCF service, communication is using SOAP over a basic http binding.
class Program
{
static void Main(string[] args)
{
RunService();
GC.WaitForFullGCComplete();
Console.ReadKey();
}
static void RunService()
{
new WebService().Create("http://localhost:50562/Service1.svc", "", "");
}
}
class WebService
{
public void Create(string url, string username, string password)
{
var binding = createBinding();
var endpoint = new EndpointAddress(new Uri(url));
var channelFactory = new ChannelFactory<IService1>(binding, endpoint);
var service = channelFactory.CreateChannel();
Console.WriteLine(service.GetData(5));
var channel = service as IClientChannel;
channel.Close();
}
/// <summary>
/// Creates the HttpBinding.
/// </summary>
/// <returns>The binding.</returns>
private BasicHttpBinding createBinding()
{
var binding = new BasicHttpBinding();
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
binding.SendTimeout = new TimeSpan(0, 1, 0);
binding.ReceiveTimeout = new TimeSpan(0, 1, 0);
return binding;
}}
I have a console application that uses the ChannelFactory to create a proxy. We make a call to the service close the connection then run GC.
The problem is that if you do a memory dump of the application at the Console.ReadKey() line at this point you can see the full SOAP request string in memory.
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><GetData xmlns="http://tempuri.org/"><value>5</value></GetData></s:Body></s:Envelope>
The question is what is keeping this in memory and how do you remove it? It's ok in this demo project but we would like to remove sensitive information (user credentials in the header) from memory in our real application.
So far I have looked at verifying we are closing the channel correctly and WCF MessageBuffers to see if these were keeping it in memory. I have also used memory profilers to try and see what this object is but with no luck. The only conclusion I have come to is it seems to be something under the hood of WCF as none of our, objects are alive at this point.
Any ideas?
The problem is that if you do a memory dump of the application at the Console.ReadKey() line at this point you can see the full SOAP request string in memory.
Try one of the following to potentially eliminate problems where message contents is visible insecurely:
message-level rather than transport-level encryption. That way the message should not be decipherable from memory
custom headers and authentication providers: by using SecureString and custom header construction you will have complete control over header formation and encryption. You can use this together with transport or further message-level encryption
The free set of steak knives here is that you enhance the message's security over the wire not just protect yourself from memory dumps.
SecureString
OP's code:
public void Create(string url, string username, string password)
Why don't you use SecureString as a parameter?
MSDN has this to say about SecureString:
SecureString is a string type that provides a measure of security. It tries to avoid storing potentially sensitive strings in process memory as plain text. More...
e.g.
public void Create(string url, string username, SecureString password) { ... }
I would be more worried that your credentials are being sent over the wire unencrypted so be sure to use message-level or transport-level encryption too.

Odd behavior using the IBM DB2 for i5/OS .NET provider dll in C#

At my company we use the IBM DB2 for i5/OS .NET provider dll version 12.0.7.3. in a web application that makes database calls to the iSeries. We encountered a situation where a method which would create a connection then pass that connection to subroutines would seem to access the wrong data sometimes. An example case is as follows: Assume the server has just spun up. Client A calls the "GetContractPdf" and it succeeds. Client B then calls the same method and it fails. The server is restarted and Client B calls the "GetContractPdf" method which then succeeds. Client A calls it and it fails.
I pulled my hair out trying to figure this out but it appears that the code isn't disposing of or handling the database connections properly. It is reproducible in my development environment and when I do reproduce it the connection object shows the right library list for the client that I used to call it, but after inserting a test query that would yield data that could easily identify the client database being touched it was absolutely getting the wrong data. The databases in question are running on the same physical AS/400 machine with different library lists. A third client who has their own AS/400 is unaffected by this problem.
I have been changing any method that accepts a connection as an argument to create their own connection and hoped that it won't cause too big of a performance hit.
Here is the method that generates the connections:
public static iDB2Connection GetConnection(string ClientCode)
{
string decrypted = "";
try
{
decrypted = System.Configuration.ConfigurationManager.ConnectionStrings[ClientCode].ConnectionString;
}
catch (Exception)
{
throw new FaultException(string.Format("Client connection string not found for {0}.", ClientCode));
}
try
{
decrypted = EncryptDecrypt.Decrypt(decrypted);
}
catch (Exception)
{
throw new FaultException(string.Format("Error determining connection string for client {0}.", ClientCode));
}
try
{
return new iDB2Connection(decrypted);
}
catch (Exception)
{
throw new FaultException("Error accessing database.");
}
}
And here is some pseudocode that shows how it is used when the problem behavior arises:
public static ContractObject GetContract(clientCode,contractId){
using(iDb2Connection conn = GetConnection(clientCode)){
ContractObject contractObject = new ContractObject(){
Id = contractId
};
GetSomeData(contractObject,conn);
GetOtherData(contractObject,conn);
return contractObject;
}
}
public static void GetSomeData(ContractObject contract, iDb2Connection connection){
string commandText = "Select data from table where conditions";
using(iDb2Command cmd = new iDb2Command(commandText,connection)){
using(iDb2DataReader reader = cmd.ExecuteReader()){
if(reader.HasRows){
contract.Foo = reader["ColumnName"].ToString();
}
}
}
}
public static void GetOtherData(ContractObject contract, iDb2Connection connection){
string commandText = "Select data from table where conditions";
using(iDb2Command cmd = new iDb2Command(commandText,connection)){
using(iDb2DataReader reader = cmd.ExecuteReader()){
if(reader.HasRows){
contract.Bar = reader["ColumnName"].ToString();
}
}
}
}
If I change the methods up so that a new connection object is created for every query the behavior is eliminated.
As I see it there are two possible problems, either I have done something horribly wrong (which I certainly could have), or the IBM dll does not handle passing around connection objects well (which you would think is less likely but could happen). I'm sure there are other possibilities that I'm too inexperienced / code blind to see.
Do any of you have any ideas of what could be causing this behavior or questions that could lead us to figuring out what causes this behavior?
Thanks in advance for your time.

Is string builder the right choice?

So from what I understand of a string vs StringBuilder is that string builder will actually modify the instance of itself while string will just make a new one. So if I understand this correctly then by using the string method for a constantly changing variable I could basically be eventually using all the memory until the computer needs to dump it to make room.
What I am doing is using an event handler to monitor serial communication. I will take in the data and parse it out plus display it in a text box. The event handler uses string to accomplish this currently. In concern for better programming and not using up all the memory when I don't need to I am trying to clean up my code.
I started to code with string builder and begun to get the build error that StringBuilder does not contain a .contains method.
Basically I am curious if i should leave it alone? Should I approach this differently? and do I have the right understanding in that string will inevitably run me out of memory?
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
rx.AppendText(Environment.NewLine + indata);
string dataCheck = indata.ToUpper();
if (dataCheck.Contains("CONNECT") || indata.Contains("CONNECTED"))
{
cState.Text = "Connected";
connectLink();
}
if (dataCheck.Contains("NO CARRIER"))
{
cState.Text = "Disconnected";
disconnect();
}
dataCheck = null;
}
You are incorrect; using String will not (in general) cause you to run out of memory.
If you're doing lots of concatenation, using string is less efficient, since it needs to build a new string and throw away the old string every time you concatenate.
In such scenarios, you should use a StringBuilder to build the string, then call ToString() whenever you want to display it.
Your code does not contain any concatenation, so using StringBuilder wouldn't do any good.

Categories

Resources