COMMUNITY

Problems with client/server authentication

Hello,

I am trying to send PUBLICKEY, SECRETKEY authentication headers from my C# code to the server on WAMP, which has PHP code generated from Haxe, and I am having trouble finding out why the headers received by the server are null.

My C# code is:

var request = (HttpWebRequest)WebRequest.Create(EndPoint + parameters);
request.Headers.Add("PUBLICKEY", PublicKey);
request.Headers.Add("SECRETKEY", SecretKey);

request.Method = Method.ToString();
request.ContentType = ContentType;

using (var response = (HttpWebResponse)request.GetResponse())
{
    var responseValue = "";

    if (response.StatusCode != HttpStatusCode.OK)
    {
        var message = string.Format("Request failed. Received HTTP {0}", response.StatusCode);
        MessageBox.Show(message, "Web Server Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        return null;
    }

    // grab the response
    using (var responseStream = response.GetResponseStream())
    {
        if (responseStream != null)
            using (var reader = new StreamReader(responseStream))
            {
                responseValue = reader.ReadToEnd();
            }
    }

    return responseValue;
}

My Haxe server code is as follows:

var cnx = sys.db.Mysql.connect({
    host : "localhost",
    port : null,
    user : "root",
    pass : "",
    database : "caj_news",
    socket : null,
});

if (cnx == null)
{
    return;
}

Manager.cnx = cnx;

var pKey = Web.getClientHeader("PUBLICKEY");
var sKey = Web.getClientHeader("SECRETKEY");

if (pKey == null)
{
    Web.setReturnCode(500);
    Lib.print("Public Key is null.");
    return;
}

if (sKey == null)
{
    Web.setReturnCode(500);
    Lib.print("Secret Key is null.");
    return;
}

I don’t even get any further than these null checks, because the server is setting the return code to 500. Now, because C# is a stupid language and throws meaningless Exceptions that tell me nothing other than System.Net.WebException: 'The remote server returned an error: (500) Internal Server Error.', I do not know which of the above two variables are null. My guess is both.

But why? I am clearly sending two headers with my response when calling MakeRequest in the following C# code:

RestClient.Client.EndPoint = "http://caj-news/admin/includes/index.php?page=";
RestClient.Client.PublicKey = "2RpDDg9NGWsUvMmwuOc3yVfP6RjF0KQXRxK7ZMWIrEVKybbzglkMMRUA8tbWMhbF";
RestClient.Client.SecretKey = "oi6dQujoTkAviIfYmBxeUhErmki9Mt5ncejiFSAKhOIHYHtbOAOqlISLaagEGM0z";
var response = RestClient.Client.MakeRequest();
if (response != null)
{
     MessageBox.Show("Authenticated successfully.");
}

I have checked the database and both these values match. I just don’t get it. Am I overlooking something obvious?

Try untyped __php__("var_dump(getallheaders())"); to see if those headers are received on a server side.

And comment out DB connection related code to make sure it’s not the reason of error 500.

Also you may check actual HTTP request/response packets using a tool like Charles Proxy

So, here is the response I got in the form of a MessageBox in WinForms:

image

Both ‘PUBLICKEY’ and ‘SECRETKEY’ are sent to the server. Would the Content-Type header affect anything? I wouldn’t have thought so for headers.

I know the server works because it’s localhost anyway.

Using a different method for obtaining the keys and I get the following:

image

I changed the Haxe code to:

var pKey = untyped __php__("$_SERVER['PUBLICKEY']");
var sKey = untyped __php__("$_SERVER['SECRETKEY']");

It’s weird, however, that despite the fact that getallheaders() is obtaining the headers as expected, that getting the headers by index doesn’t work… Very unusual…

Okay, clearly this is just me being stupid. Exceptions are such a bad way at expressing errors it’s unreal. If it wasn’t for these pathetic error messages telling me nothing of use, I could have solved this on my own which I eventually did, because it was the case that further down the line I had more Web.setReturnCode(500) calls, but the Exception’s weren’t giving me error messages or response contents of where the return code was set and what the message was from the server.

Never mind, I got there in the end.

FYI (and purely “IMHO” …), I am categorically uncomfortable seeing cipher-key material being exchanged in this way. Instead, I am of the opinion that you should strive to secure the entire connection, doing so in a way that doesn’t have to involve the server-side code directly (except for it to confirm that it’s listening to a secure connection). Further, I think that the authentication should use certificates.

For instance, "mod_ssl cuts both ways." It can verify and require the use of client-side certificates to restrict itself to certain clients and to know exactly to whom it is communicating. The entire key-exchange sequence is thus pushed into the TLS/SSL layer where it properly belongs.