SSL HttpWebRequest causes internal server error? - c#

I am trying to write a login script, but for some reason I am getting an internal server error (500).
I tried this with PHP and cURL, there I got a response when I set the option VERIFY_PEER = false.
Here's the C# code:
private void Login()
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create("https://whatever.com");
ASCIIEncoding encoding = new ASCIIEncoding();
string postData = string.Format("user={0}&password={1}&submit=login", User, Password);
byte[] data = Encoding.ASCII.GetBytes(postData);
webRequest.Method = "POST";
ServicePointManager.ServerCertificateValidationCallback = (x,y,z,a) => true;
webRequest.ContentLength = data.Length;
webRequest.KeepAlive = false;
using (Stream stream = webRequest.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
using (HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse())
{
using (StreamReader responseStream = new StreamReader(response.GetResponseStream()))
{
Console.WriteLine(responseStream.ReadToEnd());
}
}
}
Does anybody know why I am not getting a response?
Thanks for your help.

I would suggest using Fiddler to inspect the HTTP request/responses. You can set it up to intercept HTTPS traffic too. That way you can see exactly what your system is requesting.
From your comments your getting a 500 error, that normally means the url/request is malformed if it works from one script/app and not the other. This will let you see whats being request (and highlight any protocol error for you).

I found the mistake... It seems as if the server requieres a "valid" useragent. When setting firefox as a useragent, everything works fine.

Related

Weak signature algorithm is warned by browser but not via C#?

We use a third party service which - when accessed via a browser - it yields this error :
OK - we should call them and probably tell them to fix this at their side.
But -
Question:
Looking at this simple C# code - Why don't I see any exception about this warning , or in other words - How can I make C# to reflect this warning or unsafe access ?
NB I already know that I can use a more advanced webrequest class using other class - But it doesn't matter for this question. (imho).
void Main()
{
Console.WriteLine(CreatePost("https://------", "dummy")); // No exception/warning here
}
private string CreatePost(string uri, string data)
{
HttpWebRequest request = (HttpWebRequest)
WebRequest.Create(uri); request.KeepAlive = false;
request.ProtocolVersion = HttpVersion.Version10;
request.Method = "POST";
byte[] postBytes = Encoding.GetEncoding("UTF-8").GetBytes(data);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = postBytes.Length;
Stream requestStream = request.GetRequestStream();
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
// now send it
requestStream.Write(postBytes, 0, postBytes.Length);
requestStream.Close();
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
return new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("UTF-8")).ReadToEnd();
}
Also - I know that browser url address is using GET (unlike the C# post verb) - but I don't think that they've redirected this action to a silenced warning)
You don't see any warning when accessing it via C# because Google Chrome is checking how the SSL is set up and putting the warning in the way to try and protect you (and users of said service). When you access it from C#, it never touches Chrome and so you don't get the warning.
You'll get a similar warning in a few other browsers, but it's not part of the response to the request you're making - just the browser trying to keep you safe.
You could manually check the signature algorithm in your code, and throw an exception if it's not what you deem "secure".
Edit: you can check the signature algorithm by adding a custom validation callback to ServicePointManager, something like this:
ServicePointManager.ServerCertificateValidationCallback =
new RemoteCertificateValidationCallback(
(sender, certificate, chain, errors) => {
var insecureAlgorithms = new List<String> { "SHA1" };
var sslCertificate = (X509Certificate2) certificate;
var signingAlgorithm = sslCertificate.SignatureAlgorithm;
if (insecureAlgorithms.Contains(signingAlgorithm.FriendlyName))
{
return false;
}
// do some other checks here...
return true;
}
);

HttpWebRequest receives "WebException: The request timed out"

After endless research and testing of different combinations, I'm clueless right now.
I receive an WebException: The request timed out only if I my byteArray gets filled by something else than System.Text.Encoding.UTF8.GetBytes(""). (Like "hello")
The server setup is a https-request to a Google Load Balancer, which communicates with the backend via HTTP. The backend is an Apache with PHP.
For testing purposes (self-signed SSL-Cert) I have this:
System.Net.ServicePointManager.ServerCertificateValidationCallback =
delegate (object s,
System.Security.Cryptography.X509Certificates.X509Certificate certificate,
System.Security.Cryptography.X509Certificates.X509Chain chain,
System.Net.Security.SslPolicyErrors sslPolicyErrors){
return true;
};
If I enter the URL in my web-browser (Chrome), I get a response.
If I use the HTTP-requester from Mozilla with or without content to send, I get the correct response data (after adding an SSL-Security exception)
If I run my code below with System.Text.Encoding.UTF8.GetBytes("") everything works (except I cannot send data and therefore receive what I want)
Here's the code I'm using.
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create("https://someurl.com/some.php");
webRequest.Proxy = null;
webRequest.Credentials = CredentialCache.DefaultCredentials;
webRequest.Method = "POST";
webRequest.Timeout = 3000;
byte[] byteArray = System.Text.Encoding.UTF8.GetBytes("someData"); //works if empty
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.ContentLength = byteArray.Length;
Stream postData = webRequest.GetRequestStream();
postData.Write(byteArray, 0, byteArray.Length);
postData.Close();
HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse(); //ERROR MESSAGE
Stream dataStream = webResponse.GetResponseStream();
reader = new StreamReader(dataStream);
string data = reader.ReadToEnd(); //output data
reader.Close ();
dataStream.Close ();
webResponse.Close ();
The exact error (btw, all this happens in the Unity3D editor):
WebException: The request timed out
System.Net.HttpWebRequest.EndGetResponse (IAsyncResult asyncResult)
System.Net.HttpWebRequest.GetResponse ()
So why on earth is it not working, once there is something the GetRequestStream has to write?
Thanks and all the best,
Kruegbert
..::Addendum
if I increase the timeout, it just takes longer until the same msg appears.
If I write webRequest.ContentLength = byteArray.Length+1 I receive a response, but it's a WebException error: ProtocolError
If I write webRequest.ContentLength = byteArray.Length-1 I get the ProtocolViolationException
I already tried the same with try/catch/using resulting in the same behaviour
I figured out, why it was not working - still I don't know why it behaves like this. (Maybe a UnityEditor thing)
I added
webRequest.ProtocolVersion = HttpVersion.Version10;
and everything worked. No more timeout errors. And yes webRequest.ProtocolVersion = HttpVersion.Version11; results in the timeout error.
However, making a HttpRequest from the web succeeds with either of these: HTTP/1.1, HTTP/1.0 (with Host header), HTTP/1.0 (without Host header)

HttpWebRequest random 'request timed out' exception

I am currently developing in Unity (in particular using C#) and I'm stuck with HttpWebRequest - HttpWebResponse random timeouts.
I have some methods that send a POST request to a server I host on my local machine (XAMPP) to use various php scripts which are going to fetch informations from MySQL Database (hosted with XAMPP) and give back those info in JSON format.
Then I handle these JSON informations with my C# scripts.
The problem is that when I run the first test all is good:I can get the JSON data from my Server and show it in the Debug Console.
When I run the second test,a WebException is raised with error:
WebException - The request timed out
After that second test,if I run again and again,the problem keeps presenting in a random way.
I followed all the guidelines I found on the internet on how to setup a webrequest - webresponse properly,in particular I tried to use ServicePoint.DefaultConnectionLimit and ServicePoint.MaxServicePointIdleTime,without any result.
The general structure of my methods (regarding the web request/response part) is something like that:
public void WebMethod(){
string post_url = "http://localhost/service.php?someparam=1&someparam=2";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(post_url);
request.Method = "POST";
request.KeepAlive = false;
request.Timeout = 5000;
request.Proxy = null;
string Response = "";
try
{
using (HttpWebResponse resp = request.GetResponse() as HttpWebResponse)
{
using (Stream objStream = resp.GetResponseStream())
{
using (StreamReader objReader = new StreamReader(objStream, Encoding.UTF8))
{
Response = objReader.ReadToEnd();
objReader.Close();
}
objStream.Flush();
objStream.Close();
}
resp.Close();
}
}catch(WebException e)
{
Debug.Log(e.Message);
}
finally
{
request.Abort();
}
//tried this one after reading some related answers here on StackOverflow,without results
//GC.Collect();
Debug.Log("SERVER RESPONSE:" + Response);
//Response Handling
}
I know that it may be something related to a wrong abort on the HttpWebRequest / Response or maybe related to the HTTP 1.1 connections limit,but I can't figure out any solution at the moment.
Any help is appreciated.

Error while reading response from HttpWebRequest

I am trying to send contents of 1GB text file over the network. I modified the suggested code for basic authentication and kept it as follows :
WRequest = (HttpWebRequest)HttpWebRequest.Create(URL);
WRequest.Credentials = Credentials;
WRequest.PreAuthenticate = true;
WRequest.ContentType = "text/plain";
WRequest.Method = "POST";
WRequest.AllowWriteStreamBuffering = false;
WRequest.Timeout = 10000;
FileStream ReadIn = new FileStream(filename, FileMode.Open, FileAccess.Read);
ReadIn.Seek(0, SeekOrigin.Begin);
WRequest.ContentLength = ReadIn.Length;
Byte[] FileData = new Byte[ReadIn.Length];
int DataRead = 0;
Stream tempStream = WRequest.GetRequestStream();
do
{
DataRead = ReadIn.Read(FileData, 0, 2048);
if (DataRead > 0)
{
tempStream.Write(FileData, 0, DataRead);
Array.Clear(FileData, 0, 2048);
}
} while (DataRead > 0);
// The response
WResponse = (HttpWebResponse)WRequest.GetResponse();
However, now it gives me System.Net.ProtocolViolationException error : "You must write ContentLength bytes to the request stream before calling [Begin]GetResponse". I checked HttpWebRequest.BeginGetRequestResponse ... and found from debugging that the contentlength for WRequest is not -1. What else could be going wrong ? How should I get the response ?
Update :
The code which worked for small files is as followed :
WebRequest request = WebRequest.Create(url);
request.Method = "POST";
request.Credentials = Credentials;
using (StreamReader reader = new StreamReader(filename))
{
postData = reader.ReadToEnd();
}
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
request.ContentType = "text/plain";
request.ContentLength = byteArray.Length;
Stream dataStream = request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
// The response
WebResponse response = request.GetResponse();
Console.WriteLine(((HttpWebResponse)response).StatusDescription);
dataStream = response.GetResponseStream();
using (StreamReader reader = new StreamReader(dataStream))
{
responseFromServer = reader.ReadToEnd();
}
dataStream.Close();
response.Close();
The article you referenced says
If the Microsoft Internet Information Services (IIS) Web server is configured to use Basic authentication, and you must set the HttpWebRequest.AllowWriteStreamBuffering property to false, you must send a HEAD request to pre-authenticate the connection before you send the POST or PUT request.
EDIT - now with more clarification!
To restate the article, if you want to send a large file to a destination which requires basic authentication, you'll need to issue two separate requests. The key here is that you are setting PreAuthenticate = true. Read the statement literally -- by setting the property to true, you are saying that you will authenticate any requests that you make before you actually attempt them! The framework doesn't know how you want to accomplish this pre-authentication, so you need to perform that action yourself, by sending a HEAD request to the destination. Think of the HEAD HTTP method as being a prologue to the actual request - it describes (or requests information about) a particular resource.
So the process goes like this:
Make a HEAD request to http://someurl/aresource containing the credentials you want to use when making future requests from this client to that server for the listed resource
The server will respond (ideally) with "OK - you may proceed. You're authenticated"
The server immediately regrets its' decision to allow the operation as it finds itself saving a very large file :-)
I don't see you making that HEAD request anywhere in the code you posted - if it's not already there, add this at the beginning of your code (snipped from the sample article ref in OP):
//preAuth the request
// You can add logic so that you only pre-authenticate the very first request.
// You should not have to pre-authenticate each request.
WRequest = (HttpWebRequest)HttpWebRequest.Create(URL);
// Set the username and the password.
WRequest.Credentials = new NetworkCredential(user, password);
WRequest.PreAuthenticate = true;
WRequest.UserAgent = "Upload Test";
WRequest.Method = "HEAD";
WRequest.Timeout = 10000;
WResponse = (HttpWebResponse)WRequest.GetResponse();
WResponse.Close();
// Make the real request.

Problems consuming WebService in .Net (ReCaptcha)

I am having difficulty in consuming the reCaptcha Web Service using C#/.Net 3.5. Although I think the problem is with consuming web services in general.
String validate = String.Format("http://api-verify.recaptcha.net/verify?privatekey={0}&remoteip={1}&challenge={2}&response={3}", PrivateKey, UserIP, Challenge, Response);
WebClient serviceRequest = new WebClient();
serviceRequest.Headers.Add("ContentType","application/x-www-form-urlencoded")
String response = serviceRequest.DownloadString(new Uri(validate ));
It keeps telling me that the error is: nverify-params-incorrect. Which means:
The parameters to /verify were incorrect, make sure you are passing all the required parameters.
But it's correct. I am using the private key, the IP address (locally) is 127.0.0.1, and the challenge and response seem fine. However the error keeps occurring.
I am pretty sure this is a issue with how I am requesting the service as this is the first time I have actually used webservices and .Net.
I also tried this as it ensures the data is posted:
String queryString = String.Format("privatekey={0}&remoteip={1}&challenge={2}&response={3}",PrivateKey, UserIP, Challenge, Response);
String Validate = "http://api-verify.recaptcha.net/verify" + queryString;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(new Uri(Validate));
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = Validate.Length;
**HttpWebResponse captchaResponse = (HttpWebResponse)request.GetResponse();**
String response;
using (StreamReader reader = new StreamReader(captchaResponse.GetResponseStream()))
response = reader.ReadToEnd();
Seems to stall at the point where I get response.
Any advice?
Thanks in advance
Haven't worked with the recaptcha service previously, but I have two troubleshooting recommendations:
Use Fiddler or Firebug and watch what you're sending outbound. Verifying your parameters would help you with basic troubleshooting, i.e. invalid characters, etc.
The Recaptcha Wiki has an entry about dealing with development on Vista. It doesn't have to be limited to Vista, though; if you're system can handle IPv6, then your browser could be communicating in that format as a default. It appears as if Recaptcha deals with IPv4. Having Fiddler/Firebug working would tell you about those other parameters that could be causing you grief.
This may not help solve your problem but it might provide you with better troubleshooting info.
So got this working, for some reason I needed to write the request to a stream like so:
//Write data to request stream
using (Stream requestSteam = request.GetRequestStream())
requestSteam.Write(byteData, 0, byteData.Length);
Could anyone explain why this works. I didn't think I would need to do this, don't completely understand what's happening behind the scenes..
Damien's answer is correct of course, but just to be clear about the order of things (I was a little confused) and to have a complete code sample...
var uri = new Uri("http://api-verify.recaptcha.net/verify");
var queryString = string.Format(
"privatekey={0}&remoteip={1}&challenge={2}&response={3}",
privateKey,
userIP,
challenge,
response);
var request = (HttpWebRequest)HttpWebRequest.Create(uri);
request.Method = WebRequestMethods.Http.Post;
request.ContentLength = queryString.Length;
request.ContentType = "application/x-www-form-urlencoded";
using (var writer = new StreamWriter(request.GetRequestStream()))
{
writer.Write(queryString);
}
string result;
using (var webResponse = (HttpWebResponse)request.GetResponse())
{
var reader = new StreamReader(webResponse.GetResponseStream());
result = reader.ReadToEnd();
}
There's a slight difference in that I'm writing the post variables to the request, but the core of it is the same.

Categories

Resources