Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to safely read query string parameters?

We have a project that generates a code snippet that can be used on various other projects. The purpose of the code is to read two parameters from the query string and assign them to the "src" attribute of an iframe.

For example, the page at the URL http://oursite/Page.aspx?a=1&b=2 would have JavaScript in it to read the "a" and "b" parameters. The JavaScript would then set the "src" attribute of an iframe based on those parameters. For example, "<iframe src="http://someothersite/Page.aspx?a=1&b=2" />"

We're currently doing this with server-side code that uses Microsoft's Anti Cross-Scripting library to check the parameters. However, a new requirement has come stating that we need to use JavaScript, and that it can't use any third-party JavaScript tools (such as jQuery or Prototype).

One way I know of is to replace any instances of "<", single quote, and double quote from the parameters before using them, but that doesn't seem secure enough to me.

One of the parameters is always a "P" followed by 9 integers. The other parameter is always 15 alpha-numeric characters. (Thanks Liam for suggesting I make that clear).

Does anybody have any suggestions for us?

Thank you very much for your time.

like image 833
Todd Armstrong Avatar asked Dec 14 '22 06:12

Todd Armstrong


2 Answers

Upadte Sep 2022: Most JS runtimes now have a URL type which exposes query parameters via the searchParams property. You need to supply a base URL even if you just want to get URL parameters from a relative URL, but it's better than rolling your own.

let searchParams/*: URLSearchParams*/ = new URL(
    myUrl,
    // Supply a base URL whose scheme allows
    // query parameters in case `myUrl` is scheme or
    // path relative.
    'http://example.com/'
).searchParams;
console.log(searchParams.get('paramName')); // One value
console.log(searchParams.getAll('paramName'));

The difference between .get and .getAll is that the second returns an array which can be important if the same parameter name is mentioned multiple time as in /path?foo=bar&foo=baz.


Don't use escape and unescape, use decodeURIComponent. E.g.

function queryParameters(query) {
  var keyValuePairs = query.split(/[&?]/g);
  var params = {};
  for (var i = 0, n = keyValuePairs.length; i < n; ++i) {
    var m = keyValuePairs[i].match(/^([^=]+)(?:=([\s\S]*))?/);
    if (m) {
      var key = decodeURIComponent(m[1]);
      (params[key] || (params[key] = [])).push(decodeURIComponent(m[2]));
    }
  }
  return params;
}

and pass in document.location.search.

As far as turning < into &lt;, that is not sufficient to make sure that the content can be safely injected into HTML without allowing script to run. Make sure you escape the following <, >, &, and ".

It will not guarantee that the parameters were not spoofed. If you need to verify that one of your servers generated the URL, do a search on URL signing.

like image 178
Mike Samuel Avatar answered Dec 28 '22 01:12

Mike Samuel


Using a whitelist-approach would be better I guess. Avoid only stripping out "bad" things. Strip out anything except for what you think is "safe".

Also I'd strongly encourage to do a HTMLEncode the Parameters. There should be plenty of Javascript functions that can this.

like image 21
Tigraine Avatar answered Dec 28 '22 00:12

Tigraine