#TLS client authentication sends target host as plaintext

TLDR; Github repo is here; https://github.com/infiniteloopltd/SSLTest

First and foremost, I am not highlighting a security flaw in TLS, I’m just pointing out a parameter that should never be “hijacked” for purposes of client identification, since it is sent in plaintext over an TLS (aka SSL) connection, and thus easily read by anyone who may be intercepting the connection.

This example is in C#, and at TCP level, a HTTPS connection needs to call “AuthenticateAsClient” before it can exchange content with the server. This step is where the client can provide to the server an X509 client certificate, to prove who the client is. Often the client does not provide an X509 certificate, and the server must use something else to authenticate the client.

The parameters to AuthenticateAsClient as the TargetHost, and an optional list of certificates. The TargetHost parameter is meant to indicate to the server which certificate to use, but it should never be used to pass any authentication credentials, like a user id – because, as the screenshot shows, the target host is passed in plaintext, and can be intercepted.

Here is my sample client;

client.Connect("127.0.0.1", 500);
var s = client.GetStream();
var bMessage = Encoding.UTF8.GetBytes("HELLO WORLD");
var ssl = new SslStream(s);
ssl.AuthenticateAsClient("SOME SECRET INFORMATION", null, SslProtocols.Tls12, false);
ssl.Write(bMessage, 0, bMessage.Length);
ssl.Close();
s.Close();

Here, I am connecting to a local server on port 500, then using SSL (TLS) to connect to it. I authenticate as a client, passing something I shouldn’t in the Target Host.

On a seperate thread, I am listening for incomming data; and outputting it to screen, and it’s really obvious how the TargetHost appears in plain text. Note that the incomming stream is not decrypting the SSL, it is just printing it raw to the screen.

So, Once again, this isn’t anything to get worried about. By default, Http client libraries won’t expose this property, you need to be down at TCP level to change it, so you’re not likely to “accidentally” leak data this way. Generally if you are writing TCP level code, you’re heading in the wrong direction – but if you do think that this property could be a short-cut to client authentication – don’t do it!

Categories: Uncategorized

Handling the effect of HttpContext null in a separate thread in ASP.NET

If you have an ASP.NET page that needs to respond quickly, but perhaps has a slow background task to do, that would be ideal to perform in a background thread. However, suddently you find that HttpContext is null, so you can no longer access server features in the background thread.

The case could be a webhook, where a third party calls your server, and has a timeout of a few seconds before they kill the connection to your server. but you have some large processing to do, that won’t be done in time, or potentially won’t be done in time.

Otherwise, it could be just a performance optimization, you have a few things you need the user to see, but there are other tasks that can happen in the background, that the user doesn’t need to wait for.

Here’s the problematic code:

    protected void Page_Load(object sender, EventArgs e)
    {
      
        var asyncJob = new Thread(() => HandleJob());
        asyncJob.Start();
    }

    private static void HandleJob()
    {
        DoSomeLongRunningTask(HttpContext.Current.Request.QueryString["jobId"]);
    }

But this code fails, because HttpContext.Current will be null in the context of the thread. It also will fail silently, since the page will load fine.

The Fix? – move any variables that you might need to access outside of the Thread

    protected void Page_Load(object sender, EventArgs e)
    {
        var jobId = Request.QueryString["jobId"];
        var asyncJob = new Thread(() => HandleJob(jobId));
        asyncJob.Start();
    }

    private static void HandleJob(string JobId)
    {
        DoSomeLongRunningTask(JobId);
    }

Categories: Uncategorized

Get a user’s profile picture from their Email address in #PHP using AvatarAPI

The new Avatar API “v2” has code examples for cUrl (Command Line), Ruby, Python and Node, but PHP was overlooked, so here is a code example to help users get their PHP code up and running;

<?php
$email = "jenny.jones@gmail.com";


$json = '{ 
    "username" : "your-username-here",
    "password" : "yout-password-here",
    "email" : "$email"
  }'; 

$json = eval('return "' . addslashes($json) . '";');

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://avatarapi.com/v2/api.aspx',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_SSL_VERIFYPEER => false, 
  CURLOPT_POSTFIELDS => $json
));

$response = curl_exec($curl);

if (curl_errno($curl)) {
	// Optional (but recommended) error handling.
    $error_msg = curl_error($curl);
	echo $error_msg;
}

echo $response;

curl_close($curl);


?>

Note that you can remove the line CURLOPT_SSL_VERIFYPEER – I just had a local issue with SSL certs.

The output will look something like this;

{
  "Name": "",
  "Image": "https://lh3.googleusercontent.com/a-/AOh14GgoCfW3iuHPprK4x75MmdXtZ7387FvWVGt_GB5Y4A",
  "Valid": true,
  "City": "",
  "Country": "",
  "IsDefault": true
}
Categories: Uncategorized

Car Registration #API available in #Malta

Malta has a population of just over half a million inhabitants, and with the number of cars on the road at 415,000 as of March 2022 (Source CEIC data), meaning that most households have multiple cars, which is not overly surprising as as rather wealthy island nation. Today, we’ve launched our Maltese website https://www.licenseplate.mt/ that provides an API that allows users determine the make / model and VIN of vehicles registered in Malta.

Car registration plates in Malta use the /CheckMalta endpoint and return the following
information:


● Make / Model
● Year
● VIN
● Engine Size
● Engine Number
● Power
● Fuel
● Body Style
● Tonnage
● Number of Seats
● Representative image

Sample Registration Number:
JJA127


Sample Json:

{
  "Description": "PEUGEOT 307",
  "RegistrationYear": "2004",
  "CarMake": {
    "CurrentTextValue": "PEUGEOT"
  },
  "CarModel": {
    "CurrentTextValue": "307"
  },
  "MakeDescription": {
    "CurrentTextValue": "PEUGEOT"
  },
  "ModelDescription": {
    "CurrentTextValue": "307"
  },
  "VehicleIdentificationNumber": "VF33HNFUE4S024189",
  "EngineSize": "1587",
  "Power": "109",
  "FuelType": "PETROL",
  "Body": "HATCHBACK",
  "NumberOfSeats": "4",
  "EngineNumber": "10FX4X2148207",
  "Tonnage": "2",
  "ImageUrl": "http://licenseplate.mt/image.aspx/@UEVVR0VPVCAzMDc="
}
Categories: Uncategorized

Serializing a #CookieContainer in C#

If you are using C# to interact with websites, then a common pattern, is that you may log in with one request, and then perform an action with the logged in user with a second request. When you wish to repeat the action, then you may end up logging in again, even though you could have potentially recycled the session from the first log in, which saves both time, and bandwidth.

In order to do so, you will need to somehow store the cookies to disk, and then reload them for the second request.

Using XmlSerialiser in this case won’t work, since the Cookie object contains a Uri object, which is not serialisable, also JSON serialiser (Newtonsoft.JSON) is problematic, since it’s not precisely a 1:1 representation of the CookieContainer (I’m not exactly sure what it misses, please feel free to add comments below with your experience).

I found, that although marked as “obsolete” by Microsoft, the BinaryFormatter provides a faithful representation of the CookieCollection.

This is some code I wote to serialize a Cookie Collection

private static void StoreCookieCollection(IEnumerable cookies, string cookieFile)
{
	cookieFile = Path.GetTempPath() + cookieFile;
	if (File.Exists(cookieFile)) File.Delete(cookieFile);
	var formatter = new BinaryFormatter();
	var fs = new FileStream(cookieFile, FileMode.Create);
	formatter.Serialize(fs,cookies);
	fs.Close();
}

And the reverse for de-serializing it:

private static CookieCollection LoadCookieCollection(string cookieFile)
{
	cookieFile = Path.GetTempPath() + cookieFile;
	if (!File.Exists(cookieFile)) return null;
	var age = File.GetLastWriteTime(cookieFile);
	if (DateTime.Now - age > TimeSpan.FromDays(1)) return null; // a day old
	var formatter = new BinaryFormatter();
	CookieCollection cc;
	using (Stream reader = new FileStream(cookieFile, FileMode.Open))
	{
		cc = (CookieCollection)formatter.Deserialize(reader);
	}
	return cc;
}

Bon apetit!

Categories: Uncategorized

Running #Mac on #AWS

Running Mac on AWS isn’t that new, it’s been available since 2020, however, it’s a useful cost-saver for developers looking to create an iOS app without purchasing a Mac. Using this approach, you can create a remotely-accessible Mac that you can turn on and off when you need it. Theoretically, costing about $1 an hour (Effetively, the host needs to be reserved for 24 hours, so it’s more like $24 a day), which makes it more or less like the MacInCloud offering of $30 a day.

Before you can create a Mac Ec2 Instance, you need to create a Mac Dedicated host. Once this is created, you can create a Mac Ec2 Instance and apply it to the host. Once created, you can connect to it using a VNC Client (Assuming you want a GUI interface)

Copy/Pasting from AWS help, here is how you connect via VNC from Windows

2.    Run the following command to install and start VNC (macOS screen sharing SSH) from the Mac instance

sudo defaults write /var/db/launchd.db/com.apple.launchd/overrides.plist com.apple.screensharing -dict Disabled -bool false
sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.screensharing.plist

3.    Run the following command to set a password for ec2-user:

sudo /usr/bin/dscl . -passwd /Users/ec2-user

4.    [ON YOUR WINDOWS PC] Create an SSH tunnel to the VNC port. In the following command, replace keypair_file with your SSH key path and 192.0.2.0 with your instance’s IP address or DNS name.

ssh -i keypair_file -L 5900:localhost:5900 ec2-user@192.0.2.0

Note: The SSH session should be running while you’re in the remote session.

5.    Using a VNC client, connect to localhost:5900.

And then you can go ahead and install XCode and your App source code.

Don’t forget to de-allocate your dedicated host after stopping your ec2 instance, otherwise you’ll have a huge bill at the end of the month!

The overall experience is much more “clunky” and slow than a real Mac, it’s not much of a substitute, and the risk that if you forget the de-allocate the dedicated host, then it’ll cost you more than a mac itself in AWS fees.

Categories: Uncategorized

A Waterfall pattern for C#

First, let’s paint a scenario – you can query multiple sources for the same data, with the hope that one of these sources will have a response.

These sources can respond in three possible ways;

1 . An answer.

2. An exception indicating that the answer is impossible, and there is no need to query other sources

3. An exception indicating that the source failed, but perhaps another source will work.

So, Let’s define an exception of case (2)

class ExpectedException : Exception
{
}

Now, define our three sources, which must have the same input and output types, in this case they will be strings, but they could be any types, as long as they are consistent.

static string SourceA(string input)
{
	throw new Exception("Some random error");
}

static string SourceB(string input)
{
	throw new ExpectedException();
}

static string SourceC(string input)
{
	return "OK";
}

Now, we define a Waterfall function, that will call a list of functions in order, until it reaches either case (1) or case (2)

private static T1 Waterfall<T1,T2>(IEnumerable<Func<T2, T1>> waterfallFunctions, T2 parameter)
{
	var waterfallExceptions = new List<Exception>();
	foreach (var waterfallFunction in waterfallFunctions)
	{
		try
		{
			var functionResult = waterfallFunction(parameter);
			return functionResult;
		}
		catch (ExpectedException)
		{
			throw;
		}
		catch (Exception e)
		{
		   waterfallExceptions.Add(e);
		}
	}
	throw new AggregateException(waterfallExceptions);
}

Which is called as follows

var result = Waterfall( new List<Func<string, string>>
{
	SourceA,
	SourceC,
	SourceB
},"hello");

This code is available on a public Github repo here: https://github.com/infiniteloopltd/Waterfall

Hope this helps someone!

Categories: Uncategorized

A pattern for dealing with #legacy code in c#

static string legacy_code(int input)
{
	// some magic process
	const int magicNumber = 7;

	var intermediaryValue = input + magicNumber;
	
	return "The answer is " + intermediaryValue;
}

When dealing with a project more than a few years old, the issue of legacy code crops up time and time again. In this case, you have a function that’s called from lots of different client applications, so you can’t change it without breaking the client apps.

I’m using the code example above to keep the illustration simple, but you have to imagine that this function “legacy_code(int)”, in reality, could be hundreds of lines long, with lots of quirks and complexities. So you really don’t want to duplicate it.

Now, imagine, that as an output, I want to have just the intermediary value, not the string “The answer is …”. My client could parse the number out of the string, but that’s a horrible extra step to put on the client.

Otherwise you could create “legacy_code_internal()” that returns the int, and legacy_code() calls legacy_code_internal() and adds the string. This is the most common approach, but can end up with a rat’s nest of _internal() functions.

Here’s another approach – you can tell me what you think :

static string legacy_code(int input, Action<int> intermediary = null)
{
	// some magic process
	const int magicNumber = 7;

	var intermediaryValue = input + magicNumber;

	if (intermediary != null) intermediary(intermediaryValue);

	return "The answer is " + intermediaryValue;
}

Here, we can pass an optional function into the legacy_code function, that if present, will return the intermediaryValue as an int, without interfering with how the code is called by existing clients.

A new client looking to use the new functionality could call;

int intermediaryValue  = 0;
var answer = legacy_code(4, i => intermediaryValue = i);
Console.WriteLine(answer);
Console.WriteLine(intermediaryValue);

This approach could return more than one object, but this could get very messy.

Categories: Uncategorized

Using #AppsScript to call an #API from Google Sheets

AppsScript is a Macro programming language that you can use within Google Sheets to automate data entry. In this case, we want to take one cell, which contains a vehicle registration number, and run it through an API, in order to extract details, like the make / model / VIN of that car. The API providing this is available here; https://www.carregistrationapi.in (India) – Many other countries are available, like the US, UK, Australia, South Africa, etc., but this particular example is for India.

To Access the App Script “IDE” press Extensions > App-Script on your google sheet. Here I am using the code as follows:


var USERNAME = "***USERNAME GOES HERE ****";
var PASSWORD = "*** PASSWORD GOES HERE ****";


function CheckIndia(plate,property,subproperty)
{
  var userProperties = PropertiesService.getUserProperties();
  var cacheHit = userProperties.getProperty(plate);
  if (cacheHit != null)
  {
      var cacheData = JSON.parse(cacheHit);
      if(subproperty == null)
      {
        return cacheData[property];
      }
      else
      {
        return cacheData[property][subproperty];
      }
  }
  // Sample UP14CT0093
  var url = 'https://www.regcheck.org.uk/api/json.aspx/CheckIndia/' + plate;
  var headers = {
    "Authorization" : "Basic " + Utilities.base64Encode(USERNAME + ':' + PASSWORD)
  };
  var params = {
    "method":"GET",
    "headers":headers
  };
   var response = UrlFetchApp.fetch(url,params);
   var json = response.getContentText();
   userProperties.setProperty(plate,json);
   var data = JSON.parse(json);   
   if(subproperty == null)
   {
      return data[property];
   }
   else
   {
      return data[property][subproperty];
   }
}

The USERNAME / PASSWORD variables need to be taken from your registration on https://www.carregistrationapi.in .

The Function “CheckIndia” is what you call from within the Google Sheet Cell, such as:

=CheckIndia(A2,”Description”)

Here, in the example above, A2 is the cell that contains the license plate, and “Description” is the make + model of the vehicle.

There is a level of internal caching built-in so that the API is not called every single time a call is made, if the call was made elsewhere on the sheet.

Categories: Uncategorized

Determine the country code from country name in C#

If you are trying to determine the country code (“IE”) from a string like “Dublin, Ireland”, then generally the best approach is to use a Geolocation API, such as Google Geocode, or Here maps, or the plethora of others. However, if speed is more important than accuracy, or the volume of data would be too costly to run through a paid API, then here is a simple script in C# to determine the country code from a string

https://github.com/infiniteloopltd/CountryISOFromString/

The code reads from an embedded resource, which is a CSV of country names. Some of the countries are repeated to allow for variations in spelling, such as “USA” and “United States”. The list is in English only, and feel free to submit a PR, if you have more variations to add to this.

It’s called quite simply as follows;

var country = Country.FromString("Tampere, Pirkanmaa, Finland");
Console.WriteLine(country.code);
Categories: Uncategorized
%d bloggers like this: