How to authenticate Websocket connections in C# - c#

I have an HTML application.
Some pages have to run websockets to connect to a server running an Asp.Net application and send/receive some messages through Websocket.
The websockets server works fine. But anyone can send some requests to the server. I would like my server to be protected and receives only authenticated requests. For example from Javascript in Developer Mode, I can run requests against Websocket server...
So far I'm accepting requests only from my domain as follows but that is not enough :
var webSocketOptions = new WebSocketOptions()
{
KeepAliveInterval = TimeSpan.FromSeconds(120),
};
webSocketOptions.AllowedOrigins.Add("https://example.com");
webSocketOptions.AllowedOrigins.Add("https://www.example.com");
app.UseWebSockets(webSocketOptions);
Is there any way to authenticate Websocket requests ? Or for example allow only legitimate users send requests to the WS server ?
Thanks.

I hope someone else could provide more information - as I am not very familiar with WS(Web Sockets), but here what I would do (number 3 is probably what you want):
Validate Before WS connection is established - Self explanatory, don't create a WS connection if they had not authenticated via another method, but that's not always the option;
Use a specified format with a validation built it - Lets say the socket is expecting a message in the form of:
{
"Token": "27e0127341dfaojo",
"Message": "Hello World!",
"Command": "SendMessage"
}
If it is not in that format, then ignore it - and once it is, you can validate the token.
Using (Cookie Authentication) - the link explains more.

Related

How to consume a socket.io WebSocket API in C#

I need to consume a third-party WebSocket API in .NET Core and C#; the WebSocket server is implemented using socket.io (using protocol version 0.9), and I am having a hard time understanding how socket.io works... besides that the API requires SSL.
I found out that the HTTP handshake must be initiated via a certain path, which is...
socket.io/1/?t=...
...whereby the value of the parameter t is a Unix-timestamp (in seconds). The service replies with a session-key, timeout information, and a list of supported transport protocols. Due to simplicity, this first request is made via HttpClient and does not involve any additional headers.
Next, another HTTP request is required, which should result in an HTTP 101 Switching Protocol response. I specified the following headers in accordance to the previous request...
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Key: ...
Sec-WebSocket-Version: 13
...whereby the value of the Key-header is a Base64-encoded GUID-value that the server will use to calculate the Sec-WebSocket-Accept header value. I also precalculate the expected Sec-WebSocket-Accept header value, for validation...
I tried to make that request using HttpClient as well, but that does not seem to work... I actually don´t understand why, because I expect an HTTP response. I also tried to make the request using TcpClient by sending a manually prepared GET request over a SslStream, which accepts the remote certificate as expected. Sending data seems to work, but there´s no response data... the Read-method returns zero.
What do I miss here? Do I need to setup a listener for the WebSocket connection as well, and if yes how? I don´t want to implement a feature complete socket.io client, I´d just like to keep it as simple as possible to catch some events...
The best way of debugging these issues is to use a sniffer like wireshark or fiddler. Often connect using an IE and compare IE results with my application and modify my app so it works like the IE. Using WebClient instead of HttpClient will also work better because the WebClient does more automatically than the HttpClient.
A web connection uses the header of the client and the headers in the server webpage to negotiate a connection mode. Adding additional headers to you client will change the connection mode. Cookies are also used to select the connection mode. Cookies are the results of previous connection to the same server which shortens the negotiations and stores info from previous connection so less data has to be downloaded from server. The server remembers the cookies. Cookies have a timeout and is kept until timeout expires. The IE history in your client has a list of IP addresses and Net automatically sends the cookies associated with the server IP.
If a bad connection is made to the server the cookies is also bad so the only was of connection is to remove the cookie. Usually I go into the IE and delete cookies manually in the IE history.
To check if a response is good the server returns a status. A completed response contains a status 200 DONE. You can get status which are errors. You can also get a 100 Continue which means you need to send another request to get the rest of the webpage.
Http has 1.0 (stream mode) and 1.1 (chunk mode). Net library doesn't work with chunk. Chunk requires client to send message to get next chunk and I have not found a way in Net to send the next chunk message. So if a server responds with a 1.1 then you have to add to your client headers to use 1.0 only.
Http uses TCP as the transport layer. So in a sniffer you will see TCP and HTTP. Usually you can filter sniffer just to return Http and look at header for debugging. Occasionally TCP disconnects and then you have to look at TCP to find why the disconnect occurs.

How can a c# client receive http POST?

I am currently working on a simple app to make my life easier. I made an android app which lets me pick a file and uploads it to a server. I am working on a windows PC c# app that sends its ip (dynamic) and its open port to my server.
Whenever the server receives a file from my phone, I want it to send a POST request to my PC.
I am fairly new to web stuff (I have done tons of coding before though), but as far as I understand only a server can receive a POST request.
How can I make a C# server that runs on my PC with a dynamic IP and receives POST requests?
I have been struggling with this for a while now, just simple keywords I should research would be very helpful, thanks.
HTTP is a protocol which lets Web Servers and Clients communicate. It requires you to have a web server (IIS, Apache or other) to respond to client http requests.
Client can send a GET, POST and others request type messages.
The prefable way is to send a web client using a WebClient class. Here is a sample taken from another answer given by Andrew
string URI = "site.com/mail.php";
using (WebClient client = new WebClient())
{
System.Collections.Specialized.NameValueCollection postData =
new System.Collections.Specialized.NameValueCollection()
{
{ "to", emailTo },
{ "subject", currentSubject },
{ "body", currentBody }
};
string pagesource = Encoding.UTF8.GetString(client.UploadValues(URI, postData));
}
I would create some kind of server application using WebAPI, SignalIR, WCF or ASMX web services. All of these can handle server/client communication and would make it easy to communicate with your device.

Using WCF service in MonoTouch with Authentication

I am using a WCF service client generated by slsvcutil form Silverlight toolkit version 4. I've also tried version 3 with the same problems. When I use a client instance running on http with no user credentials it runs without problems. But I need to switch to https for productive servers and send user credentials that are hardcoded for my application. I use the following code for that:
var binding = new BasicHttpBinding (BasicHttpSecurityMode.TransportCredentialOnly);
var endpoint = new EndpointAddress (AppSettings.FlareEndPoint);
_service = new TopicAnalystAPIClient(binding, endpoint);
_service.ClientCredentials.UserName.UserName = "xxx";
_service.ClientCredentials.UserName.Password = "xxx";
When I call a method on that service pointing to http with no authentication it works. When I use the this code against http/https with the credential I get "There was an error on processing web request: Status code 401(Unauthorized): Unauthorized" exception. I've checked that the credentials are correct, I am able to open the service reference in my browser. I've also tried several combinations of http/https and SecurityMode value. I've also tried it on four different servers always with the same result.
What can be the problem?
A lot of permutations are possible. BasicHttpSecurityMode.TransportCredentialOnly should be usable without SSL [1] using HTTP itself. This means the server will send one (or more) authentication method(s) to the client (e.g. basic, digest, ntlm) and Mono (including MonoTouch) should be providing support for the most of them.
It is possible that the linker (if used) removes one of them. In that case you could try building and testing without linking (or skip linking of System.Net.dll).
It's also possible that the authentication method that the serve insist on is not supported. You could find which one is used by running a network trace (e.g. wireshark) or, maybe, it will show up in more details in the server log (along with the 401 error).
[1] http://msdn.microsoft.com/en-us/library/system.servicemodel.basichttpsecuritymode%28v=vs.95%29.aspx

How do I configure a C# web service client to send HTTP request header and body in parallel?

I am using a traditional C# web service client generated in VS2008 .Net 3.5, inheriting from SoapHttpClientProtocol. This is connecting to a remote web service written in Java.
All configuration is done in code during client initialization, and can be seen below:
ServicePointManager.Expect100Continue = false;
ServicePointManager.DefaultConnectionLimit = 10;
var client = new APIService
{
EnableDecompression = true,
Url = _url + "?guid=" + Guid.NewGuid(),
Credentials = new NetworkCredential(user, password, null),
PreAuthenticate = true,
Timeout = 5000 // 5 sec
};
It all works fine, but the time taken to execute the simplest method call is almost double the network ping time. Whereas a Java test client takes roughly the same as the network ping time:
C# client ~ 550ms
Java client ~ 340ms
Network ping ~ 300ms
After analyzing the TCP traffic for a session discovered the following:
Basically, the C# client sent TCP packets in the following sequence.
Client Send HTTP Headers in one packet.
Client Waits For TCP ACK from server.
Client Sends HTTP Body in one packet.
Client Waits For TCP ACK from server.
The Java client sent TCP packets in the following sequence.
Client Sends HTTP Headers in one packet.
Client Sends HTTP Body in one packet.
Client Revieves ACK for first packet.
Client Revieves ACK for second packet.
Client Revieves ACK for second packet.
Is there anyway to configure the C# web service client to send the header/body in parallel as the Java client appears to?
Any help or pointers much appreciated.
Thanks for the reply Rob, eventually I opted to use the Add Service Reference / WCF proxy generation, which does this by default. Probably because it's using newer HTTP libraries underneath.
I did have a few WCF proxy generation issues with SOAP methods that return raw arrays of complex objects (i.e.: returning an object that contains an array of objects worked fine). To get round this you either have to wrap your arrays in objects, or switch the SOAP server config from RPC to DOCUMENT (which is what we did).
I think you can use the inherited EndGetRequestStream method to hack the SoapHttpClientProtocol. Save that to a buffer until the request has finished. Then make your own stream and push it all out at once.

SSL in a C# Web Proxy; how do I determine if the request is SLL or not?

I have built a web proxy from scratch (using Socket and NetworkStream classes). I am now trying to implement SSL support for it so that it can handle HTTPS requests and responses. I have a good idea of what I need to do (using SslStream) but I don't know how to determine if the request I get from the client is SSL or not.
I have searched for hours on this subject and have been unable to find a suitable solution.
After I do this:
TcpListener pServer = new TcpListener(localIP, port);
pServer.Start(256);
Socket a_socket = pServer.AcceptSocket();
How do I know if I need to read the information using SslStream or NetworkStream?
Client will send you a CONNECT method request after this point you need to just redirect the traffic.
Sample Connect :
CONNECT www.google.com:443 HTTP/1.1
After seeing this just switch to data redirect mode. You can not intercept or read the data so you don't need to worry about SSLStream anyway, you won't touch it.
However if you want to MITM (man in the middle) then you need to switch to SSL otherwise just redirect whatever comes to the target URL and port, that's it.
Obviously client browser will popup with an SSL certificate exception if you intercept the request.
You need to add support for the CONNECT command.
http://www.codeproject.com/KB/IP/akashhttpproxy.aspx
This is why proxy clients use one proxy for HTTP and different one for HTTPS. You can't know what type of connection you're going to receive.

Categories