Old WebServices and Security

At LDC we deal with all sorts of projects from bleeding edge to stuff that I’m sure was written by the same people as made Stonehenge. One such example came our way from a large client and involved communication between an IBM ISeries and a very wide variety of other systems, the user would trigger an item of work on the Iseries which would then call all the other systems, the job its self was not an issue, BUT the security implication of it was,

because of the variety of the systems involved, web services were picked as the most universal communication method available, but the frameworks used by the various systems varied hugely, from up-to-date CXF and .NET thought AXIS 1.4 all the way down to manual text parsing (yes really), this meant that there was no way of doing session security, hell any form of security was going to be hell.

After a bit of head scratching we used a simple solution that solved the problem nicely for all.

Every web service call now contains an additional parameter that contains a hashed text string.

when a request is made from the ISeries it generates a text string according to the rules we laid down, hashes it (we used a MD5 hash*) and adds that to the webservices call, the receiving system knows the rules the Iseries used, so generates its own string to generate a matching hash, compares it to in incoming hash and if it matches then its a valid request, else just discard.

the source string needs to contain a number of different elements to be of any use, I recommend a minimum of

  • A Time Component: This will stop the key staying the same, make it as precise as you can (but beware of time zone differences and such), we used the AS400 time format to make it easy for the ISeries guys
  • An environmental component: Something that shows which area a system is on i.e. DEV/PT/LIVE etc etc so that a dev system could not communicate with a live system by accident. happily on the Iseries there is a nice 6 digit environment ID.
  • A Password: Just a nice long string that is unique to each of the target systems

Now I don’t know IBM RPG so this side was done by an extremely talented programmer called Wajid Basha (who I personally think is wasted at his current role)

he did a little generic function to generate the hash on the IBM ISeries MD5 HASH Generator Iseries.txt

and the Java to test the resultant hash:

public static boolean isRequestValidPerEnv(String hashId, String password, String IseriesEnv) {
    boolean validRequest = false;
    String currentAS400date = String.valueOf(getAs400Date(Calendar.getInstance()));
    String completedHash = "";
    try {
        //this is the simplest version probably you would want to really add more variables and maybe chop the text around as well
        //It will obviously have to match the string generation rules on the Iseries
        String original = password + IseriesEnv + currentAS400date;
        MessageDigest md;
        md = MessageDigest.getInstance("MD5");
        md.update(original.getBytes());
        byte[] digest = md.digest();
        StringBuffer sb = new StringBuffer();
        for (byte b : digest) {
            sb.append(Integer.toHexString((int) (b & 0xff)));
            //bloody Hex to String trims leading zeros
            if ( temp.length() == 1 ) {
                temp = "0" + temp;
            }
        }
        completedHash = sb.toString();
        } catch (NoSuchAlgorithmException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    if (hashId.equals(completedHash)) {
        validRequest = true;
    }
    return validRequest;
}
// if you are doing any work with IBM As400 systems then you will already have this code.
public static Long getAs400Date(Calendar dateIn) {
    if (dateIn == null)
        return null;
    Long as400dt = 0L;
    SimpleDateFormat df = new SimpleDateFormat("yyMMdd");
    int era = 0;
    if (dateIn.get(Calendar.YEAR) > 1999)
        era = 1;
    String newDate = (1 == era ? era : "") + df.format(dateIn.getTime()).toString();
    as400dt = new Long(newDate);
    return as400dt;
}

Problem solved. 🙂
Now I would not suggest this method for an externally facing system (not with md5), and its not true serious security, but given the definition:
> Security is the ability of a system to protect information and system resources with respect to confidentiality and integrity.
then its a way that will hold this system safe from internal attack.
*Yes I know MD5 has known vulnerabilities but it was one of the few hashes that all the systems involved could generate (I hate lowest common denominators but they are a factor of real life), and frankly if someone is going to the level of effort to break the hash, then they are bloody stupid as if they are attached to the internal network then there are a lot better targets.