1

If I return JSON that contains javascript from server and populate it to jqGrid via addJSONData it will be executed even I have autoencode = true in options. To prevent XSS I had to modify jqGrid´s addCell function this way

        var v,prp;
        // This if block has been added
        if(ts.p.autoencode) {
            cell = $.jgrid.htmlEncode(cell);
        }
        v = formatter(rowId,cell,pos,srvr,'add');
        prp = formatCol( pos,irow, v, srvr, rowId, true);
        return "<td role=\"gridcell\" "+prp+">"+v+"</td>";

Is this the correct way to prevent XSS or is there some other way in jqGrid to do this?

magerachi
  • 11
  • 1
  • 2

3 Answers3

1

Sorry, but I don't understand how javascript can be inside of JSON and not HTML (see "I return JSON that contains javascript"). Could you describe your scenario for Cross-Site-Scripting attack more detailed or better provide the corresponding demo?

I personally don't understand why you use addJSONData at all. My one from the first posts here on the stackoverflow was about the subject. Nevertheless I think the data will be do encoded if you use autoencode: true option. If you look at the code of addJSONData you will find the line

rowData.push( addCell(idr,v,j+gi+si+ni,i+rcnt,cur) );

which use addCell to add the cell content to the grid. The internal function addCell calls formatter which calls cellVal per default

v = cellVal(cellval);

and the cellVal(val) returns

$.jgrid.htmlEncode(val)

for any non-empty val in case of autoencode: true.

If you do see some problem or some bug in the code you should better to post the demo which can be used to reproduce the bug.

Community
  • 1
  • 1
Oleg
  • 220,925
  • 34
  • 403
  • 798
0

In our application user inputs are saved as is and returned to UI which responsibility is to encode it.

Here's example JSON data returned from server that contains javascript

{"page":1,"total":1,"records":1,"rows":[{"id":"1","cell":["10jcmjn30jjiej8l499p","NO_ALERTS:Ei hälytyksiä","<script>console.log('jep');</script>","Pentti P.","3.4.2012 15:47","Kaupunki","Teiden auraus, KLO","Muu, Moite, Kiitos","Käsittelyssä, Odottaa vastausta","Ei määritetty","Luottamuksellinen","-","0","Kirjattu","x"]}]}

I have used lots of time to make jqGrid work actually very well in our application (thanks for the great piece of software) and addJSONData has been used so I wouldn't change it without need to do it.

To the problem - in formatter

} else if($.fmatter){

is always called. In my javascript knowledge $.fmatter is always true so the last else won't ever be called. Actually it seems that the bug is in jqGrid's Formatter module not in base module.

$.fn.fmatter doesn't do any encoding. In my situation it never goes to

if ($.fn.fmatter[formatType]){

block but it always returns given cellval as is. Maybe that would be the right place to do encoding?

This is what I did to make this work in our application

$.fn.fmatter = function(formatType, cellval, opts, rwd, act) {
        // build main options before element iteration
        var v=cellval;
        opts = $.extend({}, $.jgrid.formatter, opts);

        if ($.fn.fmatter[formatType]){
            v = $.fn.fmatter[formatType](cellval, opts, rwd, act);
        } else {
            v = $.jgrid.htmlEncode(cellval);
        }

        return v;
    };
magerachi
  • 11
  • 1
  • 2
0

I have found there is a XSS flaw (at least in jqGrid 4.5.4, maybe newer versions?) due to the row's id attribute being set by data returned from an AJAX call not being appropriately cleaned (as per OWASP XSS rule 2). The problem comes from constructTr not sanitizing the id parameter*, which then goes into rowData which gets appended to a DOM element in the addJSONData function.

Unfortunately constructTr cannot be easily patched due to its scope, but you can patch the getAccessor function which typically feeds the id to constructTr.

(function(jgrid){
    var _getAccessor = jgrid.getAccessor;
    function htmlAttributeEncode (value) {
        /* your encoding function here */
        return encodedValue;
    }
    jgrid.getAccessor = function () {
        return htmlAttributeEncode(_getAccessor.apply(jgrid, arguments));
    };
})(jQuery.jgrid);

(Haven't tested that exact solution, but something like that should work.)

* Note: Other attributes are also not cleaned, but I'm not sure if they can contain raw data from the AJAX call. Worth investigating more.

Luke
  • 18,811
  • 16
  • 99
  • 115