pStorage, A PersistJS Wrapper for AJAX

I Recently came across PersistJS when I wanted to build a caching layer for AJAX response in the browser. Being a Chrome-Only guy, I automatically went for sessionStorage as my option.

Unfortunately, neither sessionStorage or localStorage are a standard that works for browsers such as the mighty (giggle) IE. So I went looking for something generic that will work cross-browser. eventually I found PersistJS, and after some testing I found that it fits my needs as it wraps around different client storage techniques which means using it will deliver on my browser agnostic needs.

Since I could not find a simple wrapper that will meet my needs, and since I saw TONS of requests for this stuff during my search, I decided to build a simple class for anyone that may need it.

PersistJS shortcomings

What I found a bit annoying in PersistJS is that it lacks:

  • Content Verification, to makes sure that the user gets a refreshed content if there is any change in the server content
  • Time To Live (TTL). as part of the concept of building local storage to cache your AJAX response, is to be able to refresh it when relevant.

pStorage

The solution I came up with uses the wonderful CryptoJS for md5 hash, and PersistJS for client storage. So I wrote a class that can be embedded in your JavaScript and allow that missing functionality. I called it pStorage.

Note, if you want to make the client storage side a bit more tamper proof, you can include a salt, and add server side code that generates the “salt” parameter in gStorage, every time that a session begins, or even force it to change after TTL. in my example here, I wanted to stay generic.

Here is the code:

/*
 * pStorage
 * --------
 * a wrapper around PersistJS an CryptoJS to allow TTL and Content Validation
 * by Barry Shteiman, 2014, ref:www.sectorix.com
 */
var pStorage = new function() {
    this.uid = 'my_pStorage';
    this.salt = '';
    this.datastore = new Persist.Store(this.uid);
    this.get = function get(key) {
        var entry = JSON.parse(this.datastore.get(key)||0);
        if (!entry) return null;
            if (entry.hash !== this.hash(entry.value + this.salt)) {
                this.datastore.remove(key);
                return null;
            }
            if (entry.ttl && entry.ttl + entry.now < this.now()) {
                this.datastore.remove(key);
                return null;
            }
            return entry.value;
    }
    this.set = function set(key,value,ttl) {
        this.datastore.set( key, JSON.stringify({
            ttl   : ttl || 0,
            now   : this.now(),
            hash  : this.hash(value + this.salt),
            value : value
        }) );
    }
    this.del = function del(key) {
        var entry = JSON.parse(this.datastore.get(key)||"0");
        if (!entry) return null;
        else {
            this.datastore.remove(key);
            return null;
        }
    }
    this.now = function now () {return+new Date}
    this.hash = function hash(value) {return CryptoJS.MD5(value).toString();}
}

Note, you can and should change the uid parameter to be unique to your application (replace ‘my_pStorage’ with the name of your application for example)

The functions  implemented are:

  • pStorage.get(key) – retrieve data, returns 0 if nothing found
  • pStorage.set(key,value,ttl) – save data in the storage
  • pStorage.del(key) – delete an item

HTML

To use the complete mechanism you will need to call both CryptoJS (either directly from googlecode or download the file) and PersistJS.

<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/md5.js"></script>
<script src="ext/js/persist-min.js"></script>


The call itself is very easy, and a simple Ajax function can be built to incorporate the functionality.

JavaScript

Here is a simple example for an Ajax call (via jQuery) that looks for the data in the client storage, and if TTL is past, if content is different, or if it simply does not have it in cache – the call goes to the Ajax call.

function cachedJsonAjax (url,ttl,params) {
    var output;
    if (pStorage.get(url) == null) {
        output = $.ajax({
            url: '/path/' + url + '.php',
            type: 'POST',
            data: params,
            dataType: 'json',
            async: false
        }).responseText;
        pStorage.set(url, output, ttl);
    } else
        output = pStorage.get(url);
    return output;
}

All that is left, is to call this function, and point it to the right server resource in order to populate the data, relying on this caching layer in the front.

While this is all extremely simple, I hope this helps someone and saves you time :)

EXIF Cross Site Scripting, PHP Fun

As most security folks know, there are numerous ways to infect computers via infected image files, that contain binary viruses which are read/invoked by different image readers or the libraries that render them.

From my perspective, looking into web application security, I had an idea..

Many websites and applications nowadays, look into the picture’s EXIF information in order to extract valuable data such as the size, date, exposure, geo location, and basically any meta piece of information. well, some of the attributes are writable :)

I decided to design an experiment that will check if we can inject code directly into an EXIF tag and see if the application interpreters will execute on it. Even though I am sure that this sort of experiment has already been done in the past, but learning through experimenting is what I live for.

The Experiment

The experiment breaks into 2 sections:

  1. Will a standard JPG accept characters that are required for a simple Cross Site Scripting attack
  2. Will industry standard interpreters execute on the EXIF tags when read

First thing I did, was to install exiftool and reading the metadata off a picture that I took with my smartphone, and looked for an updatable EXIF field. For sake of this experiment, I went for the “Comment” tag, and simply wrote “barry” in it.

readexif

As you can see, the field was updated. Now, to conclude the first part of our experiment, I updated the field with a simple XSS test string to see that its accepted. It was.

We can conclude that the EXIF field accepts any character, and in specifically a string that is required for a XSS attack.

To check the second part of our experiment, I used a PHP server on a commercial hosting service (which is running what they consider their best practice PHP deployment), uploaded the manipulated image, and created the following code to display the EXIF information:

php

 

It is important to note that exif_read_data is a standard PHP function that reads the EXIF information into an array, and I used the “echo” command to loop through the output.

Here is the result:

phpoutput

We have therefor proved the second test in the experiment, there was no problem displaying an unchecked string from EXIF and running it as standard script. the XSS vector is valid.

Who Should Care?

With many websites accepting image uploads (some through mobile interfaces), and analyzing EXIF information to determine resolution, location, owner and other pieces of data – there is a risk of a web application attack. In this case we have achieved an XSS (Cross Site Scripting) attack, but this information could have been extracted/inserted into a database – enabling SQLi (SQL Injection) attack on the database.

The underlying problem does not reside in a simple echo of the malicious string.  Meta data is usually saved within the application database, on an application that parses through this kind of information (lets take any image broker including some of your favorite mobile apps). they keep this kind of meta data for indexing and search purposes. this effectively means that one could inject a Persistent XSS or an SQLi string into the database, and have it execute under certain conditions. not a good thing.

I believe that it is important to run filter engines on EXIF metadata just as if it is a normal web attack or a script injection vector.