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.
Related
With following code I am able to track public IP changes of my desktop application. This should be able to track if either the public IP changed or the user enabled a VPN to change his public IP. This code is run on application launch and used once again when a check is needed:
public class PublicIP
{
IPAddress last_ip=null;
DateTime timestamp_lastipchange;
public void UpdateIP()
{
List<string> hosts = new List<string>()
{
"https://api.ipify.org",
"https://ipinfo.io/ip",
"https://checkip.amazonaws.com",
"https://wtfismyip.com/text",
"http://icanhazip.com"
};
using(WebClient webclient = new WebClient())
{
foreach(string host in hosts)
{
//Download each string from hosts until an IP could be fetched
try{
var newip = IPAddress.Parse(webclient.DownloadString(service)); //Downloading the string
if(!newip.IsEqual(last_ip) && last_ip!=null) timestamp_lastipchange = DateTime.Now; //Check if the ip changed, if the last known ip does not exists skipp this step
last_ip = newip; //Save last known ip
return;
}
catch { }
}
}
}
}
This approach seems to work pretty well, however during UnitTesting some workflows do not fetch a new IP:
IP change by switching networks: change gets successfully detected
IP changed by provider: change gets successfully detected
VPN was enabled when the application was launched and is then turned off:
change gets successfully detected
VPN was disabled on application start and is turned on during runtime:
change does not get detected. Webclient.DownloadString() still returns the same IP as if the VPN was not enabled.
I am not really sure what is happening in workflow nr 4. Do I have to manually select the new network interface (VPN)? Or is this a caching problem on the client/server side?
WebClient is high-level and might using static pool behind-the-scene (and also deprecated). You might try using HttpClient instead, because HttpClient handle connection via its message handler, and the default one is not static, which means this should work:
using(var httpClient = new HttpClient())
{
var newip = IPAddress.Parse(webclient.GetStringAsync(service)
.ConfigureAwait(false).GetAwaiter().GetResult());
// ...
}
Recently updated to current library 12.8 for azure queue processing.
Inserted message no longer work on existing routines as they are encoded as UTF-8 vs Base 64.
found the thread talking about this and see that MS has implemented a new method to set encoding.
https://github.com/Azure/azure-sdk-for-net/issues/10242
I am unable to set the encoding however and just need a push in the right direction.
This is a .NEt 4.8 Console Application
code I am currently using:
private static void insertQueueMessage(string messageToInsert, string queueName)
{
// Get the connection string from app settings
string connectionString = ConfigurationManager.AppSettings["StorageConnectionString"];
// Instantiate a QueueClient which will be used to create and manipulate the queue
QueueClient queueClient = new QueueClient(connectionString, queueName);
// Send a message to the queue
queueClient.SendMessage(messageToInsert);
}
What I have tried:
queueClient.SendMessage(messageToInsert,QueueMessageEncoding.Base64);
and
QueueClient queueClient = new QueueClient(connectionString, queueName,QueueMessageEncoding.Base64);
How do I code this to work?
Stupid easy answer, I feel like a dolt missing this.
QueueClient queueClient = new QueueClient(connectionString, queueName, new QueueClientOptions
{
MessageEncoding = QueueMessageEncoding.Base64
});
I have been looking into how these two new settings will effect with our c# code that connects to an ldap server and performs user lookups
Using the code below to connect to an AD i have found a few scenarios that no longer work when these settings are switched on.
private static LdapConnection ConnectAndBind(
string server,
int port,
int timeout,
string userName,
string pwd,
AuthType authType,
bool useSSL,
bool useV3)
{
var con = new LdapConnection(new LdapDirectoryIdentifier(server, port));
if (useSSL)
{
con.SessionOptions.SecureSocketLayer = useSSL;
con.SessionOptions.VerifyServerCertificate = VerifyServerCertificate;
con.SessionOptions.QueryClientCertificate = QueryClientCertificate;
}
con.Timeout = new TimeSpan(0, 0, timeout);
con.SessionOptions.ProtocolVersion = useV3 ? 3 : 2;
try
{
con.AuthType = authType;
con.Credential = new NetworkCredential(userName, pwd);
con.Bind();
}
catch (Exception e)
{
throw new ProviderException(
ProviderException.ErrorIdentifier.AuthenticationFailed,
LanguageLogic.GetString("AuthenticationProvider.ConnectError"),
e.Message);
}
return con;
}
This is used in the context of a webforms/mvc asp.net (4.5) app once connected its used to import user details in the the app
but at the moment depending on how the registry keys for the two settings on the AD server are set i am finding some situations where it does not connect (the error returned is that the supplied credentials are invalid)
The first two tables are kinda how i expected it to work with non signed/non ssl basic bind not working
how ever i cannot find a reason why when the Channel binding is set to required (table 3) it does not work for the other 3 red entries
Has any one else been working on this that could shed some light on the matter. would newer version of .net support this setting.
Thanks for any info
UPDATE 1
so i downloaded Softerra LDAP browser. i get the same results using that . so i dont think its my code.
as soon as i turn on the reg key for Channel Binding i get the specified credentials are invalid for those connection methods over SSL
i have updated the AD server with all the latest patches but no change.
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?
I've installed the M4 release of the Apache Qpid Java broker on a Windows box, and started it using the out-of-the-box configuration (via the qpid-server.bat script).
I'm now trying to publish a message to a queue using the RabbitMQ C# client library (version 1.5.3, compiled for .NET 3.0); my code is:
public void PublishMessage(string message)
{
ConnectionFactory factory = new ConnectionFactory();
factory.Parameters.VirtualHost = "...";
IProtocol protocol = Protocols.FromEnvironment();
using (IConnection conn = factory.CreateConnection(protocol, "localhost", 5672))
{
using (IModel ch = conn.CreateModel())
{
string exchange = "...";
string routingKey = "...";
ch.BasicPublish(exchange, routingKey, null, Encoding.UTF8.GetBytes(message));
}
}
}
Basically, I'm unsure what values to use for factory.Parameters.VirtualHost and the strings exchange and routingKey. I've tried various combinations, but nothing seems to work - the closest I've got is seeing the following in the Qpid server log:
2009-03-19 17:11:04,248 WARN [pool-1-thread-1] queue.IncomingMessage (IncomingMessage.java:198) - MESSAGE DISCARDED: No routes for message - Message[(HC:896033 ID:1 Ref:1)]: 1; ref count: 1
which looks as though the Qpid server is receiving the message, but doesn't know what to do with it.
Any advice on what configuration values I need in my client code (bearing in mind I'm using the default Qpid config in virtualhosts.xml) would be much appreciated. More general information on virtual hosts, exchanges, queues and routing keys, and how Qpid links them all together, would also be very useful.
Thank you in advance,
Alan
Just for reference, I managed to get this working in the end. The code below sends a message to the queue test-queue in the test.direct exchange on the localhost virtual host (all part of the default Qpid broker configuration):
public void PublishMessage(string message)
{
ConnectionFactory factory = new ConnectionFactory();
factory.Parameters.VirtualHost = "/localhost";
IProtocol protocol = Protocols.AMQP_0_8_QPID;
using (IConnection conn = factory.CreateConnection(protocol, "localhost", 5672))
{
using (IModel ch = conn.CreateModel())
{
ch.ExchangeDeclare("test.direct", "direct");
ch.QueueDeclare("test-queue");
ch.QueueBind("test-queue", "test.direct", "TEST", false, null);
ch.BasicPublish("test.direct", "TEST", null, Encoding.UTF8.GetBytes(message));
}
}
}