Friday, August 12, 2016

XPages ${} risk of code injection

While working on app optimization I experimented a bit more with 'Compute on page load' vs. 'Compute dynamically' behavior. There have been several discussions in past about possible combination of ${} and #{}, for example posts from Marky RodenSven Hasselbach and Paul Withers . What struck me today was risk of code injection.

In this app many elements are read from configuration documents that are loaded into beans and later used using ${} binding. This is recommended way as it is static information, so it's efficient. It works nicely until you insert expressions into your data. This way I realized that a lot of code is prone to code injection that can be contained either in configuration documents or any string that is stored and later read this way.

To simulate the issue I created simple page with one field, one button and one text:


All it does is saving entered value into applicationScope and then displaying it. Since the text uses ${} Compute on page load, I have to reload whole page to see the result immediately.

So now to the results. Normal user would probably enter something like 'Hi there'
But more advanced user can try 'Now is #{javascript:new Date()}'
(Also note that if you do partial refresh to the text, date gets updated as it's computed every time)

If he stops being nice to your app, he will switch to
 'You #{javascript:database.getAllDocuments().removeAll(true);'had'} data'
Once he gets bored, he can finish his job with
'You had #{javascript:sessionAsSigner.getDatabase('','names.nsf').getAllDocuments().getCount()} documents in address book, but 
now you have 0.  #{javascript:sessionAsSigner.getEffectiveUserName()} did that.'
(dev/pradny is name of the server as I signed the db with server ID as many admins do)

(one part is missing in previous example as I wasn't brave enough to run full version on my server to take a screenshot, you get the idea...).

The problem is not how you get the data, but how you use it. It can come from field, configuration or computation. With great power comes great responsibility. Just be aware that ugly things can happen, which reminds me of a question. Is your son's name really Robert';) Drop Tables?

Update (15.8.2016)
 Possible workaround in next post

2 comments:

  1. In talking to Jesse Gallagher... my impression is that the biggest risk here is data coming in from the URL. I mean I see you're point but I'm not sure I've ever used ${} to get user input and then done a full page load like that.
    I use pageControllers for everything.. inside is helper methods to easily get the URL parameter... not tested but IN THEORY we could sanitize any parameters and strip out the #{} binding.

    public String getParam(final String key) {
    if (!this.getQueryString().containsKey(key)) {
    return null;
    } else {
    String temp = this.getQueryString().get(key);
    String sanitize = temp.replaceAll("\\#\\{[^\\}]+\\}", "");

    return sanitize;
    }

    }


    @SuppressWarnings("unchecked")
    public Map getQueryString() {
    final Map qs = (Map) ExtLibUtil.resolveVariable("param");
    return qs;
    }

    ReplyDelete
    Replies
    1. Good idea, I'll have to check my projects how I deal with url parameters. I bet in some cases I may have a problem.

      Full page reload was used just to create easy demo. It doesn't matter how you get your data, so if your pageController reads a String form somewhere, it can have such problem. I bet I have problems in place, where I compute static texts from data using controller like page title or section labels.

      Delete