Easy and reasonable secure way to identify a specific network - c#

We like to enable some hidden features of our software only if it is run inside of the company network. The key requirements are:
no need for a third party library outside of DotNet 4.5.1
easy to implement (should not be more than some dozens of lines .. I don't want to reimplement a crypto library)
It should be reasonable safe:
at least: hard to reverse engineer
at best: "impossible" to break even with read-access to the source code
low maintenance overhead
Win2012-Server is available for installation of additional software (open source or own implementation prefered - server can be assumed to be safe)
What I have thought about:
Check if a specific PC is available with a known MAC or IP (current implementation, not really secure and some other flaws)
Test, if a service is available on a specific response (i.e. I send 'Hello' to MyServer:12345 - server responses with 'World')
Similar to 2nd but a more complex challenge (i.e. send a seed for a RNG to the server, verify the response)
Set up an apache with HTTPS and verify the certificate

If you use ActiveDirectory, you could add a reference to the System.DirectoryServices namespace and check
ActiveDirectorySite currentSite = ActiveDirectorySite.GetComputerSite();
then you can get a bit of information from the currentSite object and check against that. That's how I enable/disable features of an application I'm developing currently.
I also grab:
var client = Dns.GetHostEntry(Dns.GetHostName());
foreach (var ip in client.AddressList)
{
if(ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
{
ipAddress = ip;
}
}
Which you can check to make sure the client is connected with the proper protocol.

I've choosen the last option: Set up a webserver in the intranet and verify the certificate.
It was easier than expected. There are enough tutorials for setting up an apache with https for every supported OS. The self-signed certificate have a lifetime of 9999 days - should be okay until 2042. The C#-part is also reasonable small:
private static bool m_isHomeLocation = false;
public static bool IsHomeLocation
{
get
{
if (m_isHomeLocation)
return true;
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://yourLicenseServer:yourConfiguredPort");
request.ServerCertificateValidationCallback += ((s, certificate, chain, sslPolicyErrors) => true);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
response.Close();
var thumbprint = new X509Certificate2(request.ServicePoint.Certificate).Thumbprint;
m_isHomeLocation = (thumbprint == "WhateverThumbprintYourCertificateHave");
}
catch
{
// pass - maybe next time
}
return m_isHomeLocation;
}
}

Related

Change proxy setting for IE instance using Watin

I know that I can change the computers global proxy setting, Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings, to affect IE instances created using Watin.
But is there any way to intercept requests made by the IE browsers and run them through a proxy? My goal is to run multiple instances of IE, each with its own proxy, which isn't possible with my current solution above.
WatiN IE creates multiple ProcessIDs (single instance IE creates multiple process ids). in order to overwrite proxy settings just for WatiN by using Fiddler Core we need to get all child process ids which are created by WatiN IE. Helper class can be found here PInvoke: Getting all child handles of window – Svett Ralchev class. And then we check all process ids inside the BeforeRequest event and wait for watin process id to overwrite proxy settings.
private void FiddlerApplication_BeforeRequest(Session sess)
{
//Debug.WriteLine("FiddlerApplication_BeforeRequest: " + sess.LocalProcessID.ToString());
if (WatinIEprocessHolder.ContainsKey(sess.LocalProcessID))
{
//see http://stackoverflow.com/questions/14284256/how-to-manually-set-upstream-proxy-for-fiddler-core
sess["X-OverrideGateway"] = WatinIEprocessHolder[sess.LocalProcessID];
}
}
Working Test Application can be downloaded here http://www.rentanadviser.com/downloads/WatiN-2.1.0.1196.zip
Test results with different anonymous proxy below. (ipaddress=browser.Text)
Process Ids:3852,7852,, Your IP address: 119.46.110.17, Proxy:119.46.110.17:8080
Process Ids:2508,6948,, Your IP address: 178.21.112.27, Proxy:178.21.112.27:3128
Process Ids:1348,1368,, Your IP address: 122.96.59.107, Proxy:122.96.59.107:83
Process Ids:7152,5104,, Your IP address: 136.0.16.217, Proxy:136.0.16.217:3127
Process Ids:4128,3480,, Your IP address: 198.52.199.152, Proxy:198.52.199.152:7808
Process Ids:2036,7844,, Your IP address: 122.96.59.107, Proxy:122.96.59.107:82
Sample code:
private void this_FormClosing(object sender, FormClosingEventArgs e)
{
StopFiddler();
}
private void Form1_Load(object sender, EventArgs e)
{
this.FormClosing += this_FormClosing;
ProxyHolder = new List<string>();
ProxyHolder.Add("119.46.110.17:8080");
ProxyHolder.Add("178.21.112.27:3128");
ProxyHolder.Add("122.96.59.107:83");
ProxyHolder.Add("136.0.16.217:3127");
ProxyHolder.Add("198.52.199.152:7808");
ProxyHolder.Add("122.96.59.107:82");
StartFiddler();
System.Threading.Thread.Sleep(500);
for (var i = 0; i < ProxyHolder.Count; i++)
{
WhatIsMyIpThroughProxy(ProxyHolder[i]);
Application.DoEvents();
System.Threading.Thread.Sleep(500);
}
//WhatIsMyIpThroughProxy();
}
private Dictionary<int, string> WatinIEprocessHolder = new Dictionary<int, string>();
private List<string> ProxyHolder = null;
public void WhatIsMyIpThroughProxy(string ProxyIPandPort)
{
using (var browser = new IE(true))// we should not navigate now. Because we need process ids.
{
WindowHandleInfo ChildHandles = new WindowHandleInfo(browser.hWnd);
foreach (var cHandle in ChildHandles.GetAllChildHandles())
{
int pid = new WatiN.Core.Native.Windows.Window(cHandle).ProcessID;
if (WatinIEprocessHolder.ContainsKey(pid) == false)
WatinIEprocessHolder.Add(pid, ProxyIPandPort);
}
System.Text.StringBuilder processIDs = new System.Text.StringBuilder();
foreach (var k in WatinIEprocessHolder.Keys)
{
processIDs.Append(k.ToString() + ",");
//Debug.WriteLine(string.Format("{0}:{1}", k, WatinIEprocessHolder[k]));
}
//we got the process ids above. Navigate now.
browser.GoTo("http://www.rentanadviser.com/en/common/tools.ashx?action=whatismyip");
browser.WaitForComplete();
WatinIEprocessHolder.Clear();
System.Net.IPAddress ip;
if (System.Net.IPAddress.TryParse(browser.Text, out ip))
{
Debug.WriteLine(string.Format("Process Ids:{0}, Your IP address: {1}, Proxy:{2}", processIDs.ToString(), browser.Text, ProxyIPandPort));
}
else
{
Debug.WriteLine(string.Format("Process Ids:{0}, Your IP address: {1}, Proxy:{2}", processIDs.ToString(), "Failed", ProxyIPandPort));
}
}
}
private void StartFiddler()
{
FiddlerApplication.BeforeRequest += FiddlerApplication_BeforeRequest;
FiddlerApplication.Startup(8888, true, true, true);
}
private void StopFiddler()
{
FiddlerApplication.BeforeRequest -= FiddlerApplication_BeforeRequest;
if (FiddlerApplication.IsStarted())
{
FiddlerApplication.Shutdown();
}
}
private void FiddlerApplication_BeforeRequest(Session sess)
{
//Debug.WriteLine("FiddlerApplication_BeforeRequest: " + sess.LocalProcessID.ToString());
if (WatinIEprocessHolder.ContainsKey(sess.LocalProcessID))
{
//see http://stackoverflow.com/questions/14284256/how-to-manually-set-upstream-proxy-for-fiddler-core
sess["X-OverrideGateway"] = WatinIEprocessHolder[sess.LocalProcessID];
}
}
I've created an app called Process Proxifier which uses FiddlerCore to add proxy settings to the Windows applications dynamically. You can find its full source code here: https://processproxifier.codeplex.com/
Also I should mention that this solution is limited to target processes with system's default "CERN" proxy setting (which is pointed at Fiddler/FiddlerCore).
It's not possible to do that with IE or even with WebBrowser (it's just an instance of IE).
But you can manipute WebBrowser behavior to achieve your desired feature.
It's possible to write your custom WebBrowser which fetched data by sending your custom WebRequest that contain your different proxy.
How to load web browser with web response
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create("http://example.com");
webRequest.Proxy = new WebProxy(host, port);
HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse();
Stream receiveStream = response.GetResponseStream();
WebBrowser webBrowser = new WebBrowser();
webBrowser.DocumentStream = receiveStream;
WebRequest.Proxy
I know you are looking for an alternative solution without using the computers global proxy setting but I thought of adding this here so others who don't have this constraint know about it.
The solution was on your question - The Windows Registry.
It is simple to change the proxy settings globally at runtime, you need to change the registry keys you are interested in using the Microsoft.Win32.Registry class in the Microsoft.Win32 namespace.
You can find MSDN documentation for this here: http://msdn.microsoft.com/en-us/library/microsoft.win32.registry(v=vs.110).aspx
See below an example of how to do this.
RegistryKey myKey = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Your key", true);
myKey.SetValue("My String Value", "Test Value", RegistryValueKind.String);
Now to change proxy settings on the box you need to change or create the right proxy registry keys you can find all the available keys at:
MSDN Documentation - 2.2.1.10 Internet Settings.
Below is a few of the keys you need to set. Each version of IE has their own keys but the ones below are identical to all browsers.
UseProxyServer
REG_DWORD
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ProxyEnable
ProxyServerAndPort
REG_DWORD
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ProxyServer
ProxyOverride
REG_SZ
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ProxyOverride
HTTP1_1ThroughProxy
REG_DWORD
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\HTTP1_1ThroughProxy
User Specific
Please bear in mind these are Current user registry entries so you may need to set them in the context of the windows identity. Also the simplest way to see what should be the values for these keys is to apply the proxy changes on the Internet Settings dialog and check them on RegEdit.exe.
Create user automatically
This is your saving grace here because you can run your process for watin on a local windows account with the settings that way you dont need to change your own proxy settings.
You can then have one user called WatinUser that the proxy settings are set against you can automate the creation of this user using the System.DirectoryServices.AccountManagement Namespace classses.
See examples here at SO: create local user account
There are products like Proxifier that let you setup rules to route traffic to different proxies based on application names, IP addresses, hostnames and port numbers. This would not let you use different proxies for multiple IE processes, but if those processes were accessing different URLs you could route the traffic through separate proxy servers. Proxifier works using the WinSocks stack, similar to what many antivirus use, and it is transparent to the application layer.
Another suggestion is to write your own web request interceptor/proxy server that will grab proxy server info from requested url and forward normalized url to the real proxy server.
for e.g. from watin you launch url "someurl?ProxyServer=10.10.10.12" now this will be intercepted by your own proxy server and it will use the proxy server param to redirect requested url i.e. "someurl" to 10.10.10.12 your proxy server implementation can set proxy details at run time and fetch the results from your server using dynamic proxy.
I hope it makes some sense.

c# Retrieving a Certificate from an SSL stream shows different chain results vs other external tools

I am working on a build a tool to test all my SSL certificates in my environment.
I am using the standard SSLStream implementation to connect to the remote servers, authenticate as a client and then use the ssl.RemoteCertificate method to retrieve the Cert.
The code works fine, I get the cert. I build a chain from the cert, loop through the chain and enumerate all the certs in the chain.
I thought that I had gotten it working until I compared my output to DigiCerts SSL Utility.
I noticed that the chains that I got from it are different than the chain that I built through C#.
Digging a little more, I realized that, in my local store where the C# code is executed, there are multiple intermediate certs with the same subject name.
The only difference is there expiry.....
it appears that C# takes the newest cert with the oldest expiry....
4/29/2017
Where as the DigiCert tool displays the intermediate cert that is older with the expiry that is closer to expiring IE 4/29/2014
Is there a way to control how the chain is built? (inside of C#)
using (TcpClient client = new TcpClient())
{
try
{
client.Connect("servername", 443);
SslStream ssl = new SslStream(client.GetStream(), false, new RemoteCertificatValidationCallback(ValidateServerCertificate), null);
ssl.AuthenticateAsClient("servername");
cert = new X509Certificate2(ssl.RemoteCertificate);
PrintChain(cert);
}
catch(Exception ex)......
}
private static void PrintChain(X509Certificate cert)
{
X509Chain ch = new X509Chain();
ch.Build(cert);
ch.ChainPolicy.RevocationMode = X509RevocationMode.Online;
foreach (X509ChainElement element in ch.ChainElements)
{
Console.WriteLine(element.Certificate.SerialNumber);
// Go thru and print all my details and continue the loop
}
I have also overridden the ValidateServerCertificate method and used the chain directly from that override instead of using the X509Cahin.Build();
they print out the same.....
Thank you

How do I check the network connection win the fatest way?

I'm developing an application for Honeywell Dolphin 6100, a mobile computer with a barcode scanner that uses Windows CE 5.0 like OS.
I want to use a function which can check the network connection existence, I tried to use the code below but its too slow.
public static bool CheckForInternetConnection()
{
string url = "http://www.Microsoft.com/";
try
{
System.Net.WebRequest myRequest = System.Net.WebRequest.Create(url);
System.Net.WebResponse myResponse = myRequest.GetResponse();
}
catch (System.Net.WebException)
{
return false;
}
return true;
}
Any one have an idea for a faster way to do that. I mention that I'm working with VS2008 on win7
Since you're not doing anything with the content of the response, there's really no reason to request it, and wait for the network transfer of all that data. You might try setting myRequest.Method = "HEAD", which will just return headers (assuming the web server supports it), but obviously still verify that you can communicate with the remote web server.
http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.method.aspx
Assuming availability on your version of the .net runtime, you can call the static System.Net.NetworkInformation.GetIsNetworkAvailable() method. There are scenarios where that'll return true and you won't be able to route to the outside world, but it'll tell you whether your device has a network interface that's marked as being up.

X509Certificate2.Verify() method always return false for the valid certificate

I am using smart card for authentication.
The SecurityTokenService (authentication service) is hosted on my machine only. The smart card has a valid certificate and it's root certificate is also installed in Local Computer store on my machine.
When I use X509Certificate2.Verify method to validate the certificate in my service, it always return false.
Can someone help me to understand why X509Certificate2.Verify() method always return false?
Note:
I used X509Chain and checked for all the flags (X509VerificationFlags.AllFlags). When I build the chanin, it returns true with ChainStatus as RevocationStatusUnknown.
EDIT 1:
I observed that X509Certificate2.Verify() method returns true if i write this code in windows form application. It returns false only in the service side code. Why so? Strange but true!
The X509VerificationFlags values are suppressions, so specifying X509VerificationFlags.AllFlags actually prevents Build from returning false in most situations.
The RevocationStatusUnknown response seems particularly relevant. Whichever certificate it is reporting that for cannot be verified to be not revoked. The Verify method can be modeled as
public bool Verify()
{
using (X509Chain chain = new X509Chain())
{
// The defaults, but expressing it here for clarity
chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot;
chain.ChainPolicy.VerificationTime = DateTime.Now;
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag;
return chain.Build(this);
}
}
Which, since it is not asserting X509VerificationFlags.IgnoreCertificateAuthorityRevocationUnknown or X509VerificationFlags.IgnoreEndRevocationUnknown while requesting an X509RevocationMode other than None, fails.
First, you should identify which certificate(s) in the chain is(/are) failing:
using (X509Chain chain = new X509Chain())
{
// The defaults, but expressing it here for clarity
chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot;
chain.ChainPolicy.VerificationTime = DateTime.Now;
chain.Build(cert);
for (int i = 0; i < chain.ChainElements.Count; i++)
{
X509ChainElement element = chain.ChainElements[i];
if (element.ChainElementStatus.Length != 0)
{
Console.WriteLine($"Error at depth {i}: {element.Certificate.Subject}");
foreach (var status in element.ChainElementStatus)
{
Console.WriteLine($" {status.Status}: {status.StatusInformation}}}");
}
}
}
}
If you look at any failing certificate in the Windows CertUI (double-click the .cer in Explorer or in the Certificates MMC Snap-In), look for a field named "CRL Distribution Points". These are the URLs that will be retrieved during runtime. Perhaps your system has a data egress restriction that doesn't allow those particular values to be queried for. You can always try issuing a web request from your web service to see if it can fetch the URLs without the context of being in the certificate subsystem.
I think, the problem is due to the proxy server and some security settings in my organization. I cannot give valid reason why it works from WinForm client and why does not from code hosted under IIS.
But the fact I want to let readers know is that Verify() method worked on server side code too when I hosted service in IIS running on the machine outside my usual domain! So you may check if the firewall settings of your domain/organization is coming in you way.

WCF WebService Security: How do I use security on a WebService?

I created a simple .NET WebService (it just passes back a string). How do I modify the server side (and possibly the client side) so that it also uses a username/password to validate before sending a response?
Client Code:
static void Main(string[] args)
{
UpdateClient client = new UpdateClient("UpdateSOAPIIS");
client.ClientCredentials.UserName.UserName = "Michael";
client.ClientCredentials.UserName.Password = "testpassword";
String response = client.GetString("New York, NY");
Console.WriteLine(response);
if (client != null) client.Close();
}
Server Code:
public virtual GetStringResponse GetString(GetStringRequest request)
{
return new GetStringResponse("Search Location: " + request.location);
}
I recommend reading Juval Lowy's excellent article Declarative WCF Security. He describes five common scenarios (intranet, internet, b2b, anonymous, no security at all) and shows what that means, how to accomplish that etc.
He even goes as far as creating declarative attributes that you can basically just put on your service declaration and be done with it.
Those security scenario should really cover at least 80%, if not 95% of your typical cases. Study them and use them! Highly recommended
It really depends on what kind of security you want. Should the protocol be encrypted, should the data be encrypted, or do you just want to authenticate a user. In the last case you can just go ahead and use whatever technology you want to verify that the user has permissions to use the API. For other options and some code, check out this MSDN article http://msdn.microsoft.com/en-us/library/ms731925.aspx

Categories

Resources