a53b9958fa734f73aeffb9ddfe2fbad1ca65f90c galt Mon Jan 30 16:18:41 2017 -0800 Check-in of CSP2 Content-Security-Policy work. All C-language CGIs should now support CSP2 in browser to stop major forms of XSS javascript injection. Javascript on pages is gathered together, and then emitted in a single script block at the end with a nonce that tells the browser, this is js that we generated instead of being injected by a hacker. Both inline script from script blocks and inline js event handlers had to be pulled out and separated. You will not see js sprinkled through-out the page now. Older browsers that support CSP1 or that do not understand CSP at all will still work, just without protection. External js libraries loaded at runtime need to be added to the CSP policy header in src/lib/htmshell.c. diff --git src/hg/hgGenome/mainPage.c src/hg/hgGenome/mainPage.c index 7b982f9..1b3bed8 100644 --- src/hg/hgGenome/mainPage.c +++ src/hg/hgGenome/mainPage.c @@ -334,70 +334,70 @@ gl->betweenChromOffsetY + yOffset, innerHeight, color, j==0, j==1, firstInRow); firstInRow = FALSE; } } yOffset += oneRowHeight; } hvGfxBox(hvg, 0, 0, gl->picWidth, 1, MG_GRAY); hvGfxBox(hvg, 0, gl->picHeight-1, gl->picWidth, 1, MG_GRAY); hvGfxBox(hvg, 0, 0, 1, gl->picHeight, MG_GRAY); hvGfxBox(hvg, gl->picWidth-1, 0, 1, gl->picHeight, MG_GRAY); hvGfxClose(&hvg); } -void graphDropdown(struct sqlConnection *conn, char *varName, char *curVal, char *js) +void graphDropdown(struct sqlConnection *conn, char *varName, char *curVal, char *event, char *js) /* Make a drop-down with available chrom graphs */ { int totalCount = 1; char **menu, **values; int i = 0; struct slRef *ref; for (ref = ggList; ref != NULL; ref = ref->next) { struct genoGraph *gg = ref->val; if (gg->isComposite == FALSE) totalCount++; } AllocArray(menu, totalCount); AllocArray(values, totalCount); menu[0] = "-- nothing --"; values[0] = ""; for (ref = ggList; ref != NULL; ref = ref->next) { struct genoGraph *gg = ref->val; if (gg->isComposite == FALSE) { ++i; menu[i] = gg->shortLabel; values[i] = gg->name; } } -cgiMakeDropListFull(varName, menu, values, totalCount, curVal, js); +cgiMakeDropListFull(varName, menu, values, totalCount, curVal, event, js); freez(&menu); freez(&values); } -void colorDropdown(int row, int col, char *js) +void colorDropdown(int row, int col, char *event, char *js) /* Put up color drop down menu. */ { char *varName = graphColorVarName(row, col); char *curVal = graphColorAt(row, col); -cgiMakeDropListFull(varName, allColors, allColors, ArraySize(allColors), curVal, js); +cgiMakeDropListFull(varName, allColors, allColors, ArraySize(allColors), curVal, event, js); } static void addThresholdGraphCarries(struct dyString *dy, int graphRows, int graphCols, boolean cgaOnly) /* Add javascript that carries over threshold and graph vars * to new form. */ { if (cgaOnly) return; jsTextCarryOver(dy, getThresholdName()); int i,j; for (i=0; i<graphRows; ++i) for (j=0; j<graphCols; ++j) { jsDropDownCarryOver(dy, graphVarName(i,j)); jsDropDownCarryOver(dy, graphColorVarName(i,j)); @@ -424,53 +424,55 @@ static char *onChangeOrg(int graphRows, int graphCols, boolean cgaOnly) /* Return javascript executed when they change organism. */ { struct dyString *dy = onChangeStart(graphRows, graphCols, cgaOnly); jsDropDownCarryOver(dy, "clade"); jsDropDownCarryOver(dy, "org"); dyStringAppend(dy, " document.hiddenForm.db.value=0;"); return jsOnChangeEnd(&dy); } static void saveOnChangeOtherFunction(int graphRows, int graphCols, boolean cgaOnly) /* Write out Javascript function to save vars in hidden * form and submit. */ { -struct dyString *dy = dyStringNew(0); +struct dyString *dy = dyStringNew(4096); +dyStringAppend(dy, +"var submitted=false;\n" +"function changeOther()\n" +"{\n" +"if (!submitted)\n" +" {\n" +" submitted=true;\n" +" "); addThresholdGraphCarries(dy, graphRows, graphCols, cgaOnly); jsDropDownCarryOver(dy, "clade"); jsDropDownCarryOver(dy, "org"); jsDropDownCarryOver(dy, "db"); -char *js = jsOnChangeEnd(&dy); -chopSuffixAt(js, '"'); -hPrintf("<SCRIPT>\n"); -hPrintf("function changeOther()\n"); -hPrintf("{\n"); -hPrintf("if (!submitted)\n"); -hPrintf("{\n"); -hPrintf("submitted=true;\n"); -hPrintf("%s\n", js); -hPrintf("}\n"); -hPrintf("}\n"); -hPrintf("</SCRIPT>\n"); +dyStringAppend(dy, "document.hiddenForm.submit();\n"); +dyStringAppend(dy, +" }\n" +"}\n" +); +jsInline(dy->string); } static char *onChangeOther() /* Return javascript executed when they change database. */ { -return "onChange=\"changeOther();\""; +return "changeOther();"; } boolean renderGraphic(struct sqlConnection *conn, char *psOutput) /* draw just the graphic */ { struct genoLay *gl; int graphRows = linesOfGraphs(); int graphCols = graphsPerLine(); boolean result = FALSE; if (ggList != NULL) { /* Get genome layout. This can fail so it is wrapped in an error * catcher. */ struct errCatch *errCatch = errCatchNew(); if (errCatchStart(errCatch)) @@ -560,43 +562,43 @@ { cgaOnly = TRUE; } jsInit(); saveOnChangeOtherFunction(graphRows, graphCols, cgaOnly); char *jsOther = onChangeOther(); /* Print clade, genome and assembly line. */ hPrintf("<TABLE>"); boolean gotClade = hGotClade(); if (gotClade) { hPrintf("<TR><TD><B>clade:</B>\n"); - printCladeListHtml(hGenome(database), onChangeClade(graphRows, graphCols, cgaOnly)); + printCladeListHtml(hGenome(database), "change", onChangeClade(graphRows, graphCols, cgaOnly)); htmlNbSpaces(3); hPrintf("<B>genome:</B>\n"); - printGenomeListForCladeHtml(database, onChangeOrg(graphRows, graphCols, cgaOnly)); + printGenomeListForCladeHtml(database, "change", onChangeOrg(graphRows, graphCols, cgaOnly)); } else { hPrintf("<TR><TD><B>genome:</B>\n"); - printGenomeListHtml(database, onChangeOrg(graphRows, graphCols, cgaOnly)); + printGenomeListHtml(database, "change", onChangeOrg(graphRows, graphCols, cgaOnly)); } htmlNbSpaces(3); hPrintf("<B>assembly:</B>\n"); -printAssemblyListHtml(database, jsOther); +printAssemblyListHtml(database, "change", jsOther); hPrintf("</TD></TR>\n"); hPrintf("</TABLE>"); if (cgaOnly) { if (count > 500) /* Too-many-chrom assembly */ { warn("Sorry, too many chromosomes. " "This one has %d. Please select another organism or assembly.", count); } else if (count == 0) /* non-chrom assembly */ { warn("Sorry, can only do genome layout on assemblies mapped to chromosomes. " "This one has no usable chromosomes. Please select another organism or assembly."); @@ -606,50 +608,51 @@ { /* Draw graph controls. */ hPrintf("<TABLE>"); for (i=0; i<graphRows; ++i) { hPrintf("<TR>"); hPrintf("<TD><B>graph</B></TD>"); for (j=0; j<graphCols; ++j) { char *varName = graphVarName(i,j); char *curVal = cartUsualString(cart, varName, ""); if (curVal[0] != 0) ++realCount; hPrintf("<TD>"); - graphDropdown(conn, varName, curVal, jsOther); + graphDropdown(conn, varName, curVal, "change", jsOther); hPrintf(" <B>in</B> "); - colorDropdown(i, j, jsOther); + colorDropdown(i, j, "change", jsOther); if (j != graphCols-1) hPrintf(","); hPrintf("</TD>"); } hPrintf("</TR>"); } hPrintf("</TABLE>"); cgiMakeButton(hggUpload, "upload"); hPrintf(" "); cgiMakeButton(hggImport, "import"); hPrintf(" "); cgiMakeButton(hggConfigure, "configure"); hPrintf(" "); cgiMakeOptionalButton(hggCorrelate, "correlate", realCount < 2); hPrintf(" <B>significance threshold:</B>"); - hPrintf("<INPUT TYPE=\"TEXT\" NAME=\"%s\" SIZE=\"%d\" VALUE=\"%g\"", - getThresholdName(), 3, getThreshold()); - hPrintf(" onchange=\"changeOther();\" onkeypress=\"return submitOnEnter(event,document.mainForm);\">"); + hPrintf("<INPUT TYPE=\"TEXT\" NAME=\"%s\" id='%s' SIZE=\"%d\" VALUE=\"%g\">" + , getThresholdName(), getThresholdName(), 3, getThreshold()); + jsOnEventById("change" , getThresholdName(), "changeOther();"); + jsOnEventById("keypress", getThresholdName(), "return submitOnEnter(event,document.mainForm);"); hPrintf(" "); cgiMakeOptionalButton(hggBrowse, "browse regions", realCount == 0); hPrintf(" "); cgiMakeOptionalButton(hggSort, "sort genes", realCount == 0 || !hgNearOk(database)); hPrintf("<BR>"); hPrintf("<TABLE CELLPADDING=2><TR><TD>\n"); boolean result = renderGraphic(conn, NULL); hPrintf("</TD></TR></TABLE>\n"); if (result) /* Write a little click-on-help */ hPrintf("<i>Click on a chromosome to open Genome Browser at that position.</i>");