Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Content Security Policy, including moving all CSS and JS to external files #966

Merged

Conversation

candrews
Copy link
Contributor

A strict content security policy is increasingly required and expected. This PR allows JavaMelody to function when a strict CSP is set, and in also sets a strict CSP for JavaMelody itself by default.

I've tested this pretty well on my own system, clicking around and checking various things to ensure everything looks and works correctly. There are no functional or visual changes; if I've done this right, you shouldn't be able to tell that I've done anything at all. :)

  • Add a configuration option for CSP header (enabled by default)
  • Eliminate all inline script and styles

Completes the work started in #782

@candrews
Copy link
Contributor Author

@evernat have you had a chance to look at this PR? I'm eager to address any feedback in order to get this work merged - thank you again!

@evernat
Copy link
Member

evernat commented Dec 2, 2020

I looked at the PR, thank you for that. There is much to read and to test.

@candrews
Copy link
Contributor Author

candrews commented Dec 7, 2020

There is much to read and to test.

Yeah, it's a big one...

Is there anything I can do to help? As I mentioned, I'm quite eager to get this merged :)

@evernat
Copy link
Member

evernat commented Dec 9, 2020

The PR is not bad, but there are things broken by the PR. It needs tests and I will try to list some issues.

@candrews
Copy link
Contributor Author

candrews commented Dec 9, 2020

The PR is not bad

🎉

but there are things broken by the PR.

:( I'm eager to eager what so I can address those issues.

It needs tests and I will try to list some issues.

Do you mean some kind of automated tests are required? I don't see any testing framework in JavaMelody.

@evernat
Copy link
Member

evernat commented Dec 9, 2020

When having Maven versions in the webapp and when choosing a period by version at the top of the main report, it does nothing. It should refresh the page with the period of the version.
After opening the "Database" report in "System informations", choosing a database report in the list does nothing. It should refresh the page to display the choosen report.
Both are because the browser blocks inline scripts still written with "onchange".

@evernat
Copy link
Member

evernat commented Dec 9, 2020

Do you mean some kind of automated tests are required? I don't see any testing framework in JavaMelody.

There is junit. But given it's JS and CSP, I was speaking of manual tests.

@evernat
Copy link
Member

evernat commented Dec 9, 2020

When clicking on "Execute the garbage collector", the confim message displays <br> instead of a line break.

@evernat
Copy link
Member

evernat commented Dec 9, 2020

In the Threads details, clicking on the "Send a thread interrupt signal" or "Kill the tread" actions display a confirm message "null" instead of "Do you confirm ..." and "... Do you really want ..."

about:blank works for all browsers and doesn't use inline javascript
therefore doesn't violate a content security policy which prohibits
inline script.
innerHTML is unsafe; use document.createElement to create elements then
set attributes on them.
Move the BOOMR.init call to boomerang.min.js and include
boomerang.min.js using a script tag.
Use attributes on the script tag to pass necessary data to the script
which is used to call BOOMR.init.
Move all inline CSS and inline Javascript to monitoring.css and
monitoring.js
Since no javascript is dynamically generated, methods to escape
javascript are no longer necessary or used.
@candrews
Copy link
Contributor Author

When having Maven versions in the webapp and when choosing a period by version at the top of the main report, it does nothing. It should refresh the page with the period of the version.
After opening the "Database" report in "System informations", choosing a database report in the list does nothing. It should refresh the page to display the choosen report.
Both are because the browser blocks inline scripts still written with "onchange".

I missed onchange - thank you for pointing those out. I've now addressed them.

When clicking on "Execute the garbage collector", the confim message displays <br> instead of a line break.

Fixed

In the Threads details, clicking on the "Send a thread interrupt signal" or "Kill the tread" actions display a confirm message "null" instead of "Do you confirm ..." and "... Do you really want ..."

Fixed

I've now addressed everything you reported; if you have any more findings or other feedback, please let know!

@candrews
Copy link
Contributor Author

candrews commented Jan 4, 2021

Happy 2021! 🥳

I have my 🤞 that the merging of this PR will be a great new start to the new year!

@candrews
Copy link
Contributor Author

@evernat could you please take another look at this PR?

@candrews
Copy link
Contributor Author

Hello @evernat - please let me know if there's anything I can do to help this PR along

@evernat
Copy link
Member

evernat commented Jan 24, 2021

I have made some tests and there are some issues:

  1. In the database reports, the list to choose the database report does not work, That's because there is &amp; in the URL instead of &. See http://javamelody.org/demo/monitoring?part=database
  2. The Other charts link on the right does not work well: it displays the other charts but the items do not scroll below the charts like in http://javamelody.org/demo/monitoring.
  3. The slider to zoom the graph does not work like it does in http://javamelody.org/demo/monitoring?part=graph&graph=usedMemory. The image should be zoomed with a new URL like http://javamelody.org/demo/monitoring?graph=usedMemory&width=1480&height=662
  4. When clicking on Details in System information, just above Threads, the Threads part slips on the right, but it shoud not, see http://javamelody.org/demo/monitoring

@candrews
Copy link
Contributor Author

I have made some tests and there are some issues:

1. In the database reports, the list to choose the database report does not work, That's because there is `&amp;` in the URL instead of `&`. See http://javamelody.org/demo/monitoring?part=database

I've pushed a fix for this issue.

2. The `Other charts` link on the right does not work well: it displays the other charts but the items do not scroll below the charts like in http://javamelody.org/demo/monitoring.

I've pushed a fix for this issue.

3. The slider to zoom the graph does not work like it does in http://javamelody.org/demo/monitoring?part=graph&graph=usedMemory. The image should be zoomed with a new URL like http://javamelody.org/demo/monitoring?graph=usedMemory&width=1480&height=662

I can't reproduce this one. I moved the slider and I can see that the image src keep changing, and does do in the same way as the demo site does.

4. When clicking on Details in System information, just above Threads, the Threads part slips on the right, but it shoud not, see http://javamelody.org/demo/monitoring

I've pushed a fix for this issue.

Thanks again for pointing out these issue - hopefully we're close to being able to merge this now 🤞

@candrews
Copy link
Contributor Author

@evernat friendly bump - I'd love to make progress and get this change merged, thanks again!

@candrews
Copy link
Contributor Author

@evernat is there anything I can do to help this along?

@evernat
Copy link
Member

evernat commented Mar 7, 2021

Sorry for the delay.
I have made some tests and I have some issues:

  1. When I see the parameter content-security-policy I would think that the value should be default-src 'self'; object-src 'none';. So it may be better to rename it to content-security-policy-enabled. (true by default)
  2. When I click on some actions such as Run GC. There is no more message giving the result of the action. It suppose that it is related to htmlCoreReport.toHtml(message, anchorNameForRedirect); replaced by htmlCoreReport.toHtml(); in the PR.
  3. When the monitoring page is loaded, graphs of http and sql requests for example are loaded with URL like .../monitoring?graph=http211e03eeda2e3305b34429bf203bbe8e280d4664&width=100&height=50. Those graphs of http and sql requests should be loaded only when the mouse hovers over each request in the details in http and sql statistics. It is related to <img src='?graph= and the removing of the onmouseover script in the PR. That's important because on some applications there may up to 10000 http requests and 10000 sql requests in the statistics.
  4. There are at least one issue with content-security-policy: in HtmlMBeansReport, there is still an inline <style type='text/css'>

@evernat evernat changed the base branch from master to content-security-policy April 5, 2021 19:33
@evernat evernat merged commit a5b35f1 into javamelody:content-security-policy Apr 5, 2021
@evernat
Copy link
Member

evernat commented Apr 5, 2021

Hi,
There are still issues with encoding. In particular, StringIndexOutOfBoundsException when a confirm message contains a quote, now encoded as &#39;, because keys between # are intended to be translations keys in write*. For example, in the confirm message for GC in French.
Ignoring &# in the translation code is not a solution, because there would be &#39; in confirm messages anyway.

So my plan is:

  • I cut a release now, because it is overdue by too many months. I can still make another release when the content-security-policy work is ready.
  • I have merged the PR in the content-security-policy branch for reference.
    Then probably:
  • I merge some bits such as moving some inline styles to css and moving some inline scripts to js files, to make the PR to come more readable. Of course, I say in the commits your github id and that it is based on this PR. And I rebase the branch with that.
  • I look again at which encoding methods are used where and what is broken by what, in order to fix the branch.
  • I add something like writeHtmlBegin before writeMessageIfNotNull in CollectorController.writeMessage.

The work in this PR is already huge and probably the bigger I have seen in a PR for javamelody. It's not bad if it is not ready yet given the task that it is.

@candrews
Copy link
Contributor Author

candrews commented Apr 7, 2021

The # issue can be easily fixed by using a different character representation. I've submitted a PR at #1003 that does just that.

I'm sorry I keep having issues... without comprehensive tests and since I'm not fully familiar with all of the functionality across the entire interface, it's really hard for me to find all the problems. I'm trying though!

Do you have any other issues? I'll happily fix them.

If you'd like the commits rebased for clarity, I can do that. I was (and still am) unclear on if you intend to squash all the commits.

I really want to get this into JavaMelody. I've been trying for almost 6 months; it's important to myself and my colleagues. Can we do anything to accelerate the process?

@evernat
Copy link
Member

evernat commented Apr 7, 2021

Given the number of commits in the branch, yes the commits would be squashed to be merged.
But I plan first to commit some css and js changes from the branch and then to rebase the branch.
The branch will be merged after a final review.

@@ -197,16 +198,16 @@ private void writeJCacheKeys(JCacheInformations jcacheInformations) throws IOExc
writeDirectly(htmlEncodeButNotSpace(myKey));
writeDirectly("</td>");
if (systemActionsEnabled) {
writeDirectly("<td class='noPrint' style='text-align: center;'>");
writeDirectly("<td class='noPrint containingIcon'");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

> was missing here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch, thank you!

@srsouto
Copy link

srsouto commented Jun 21, 2021

Is there a status on the merge of the rest of this branch? I'm seeing that the css and js externalize work was merged, but has the CSP implementation been pushed through?

@tonylulciuc
Copy link

tonylulciuc commented Jun 23, 2021

@evernat Do you know the state of this merged code?

@candrews
Copy link
Contributor Author

This hasn't actually been merged to master - it's been "merged" to a branch: https://github.com/javamelody/javamelody/tree/content-security-policy

I don't know if or when @evernat intends to merge this work to master and include it in a release, nor do I know what's blocking it. I've been trying to get this done for 7 months but @evernat is very slow to respond and I'm honestly not sure how to progress this. I'm starting to think CSP will simply never happen in JavaMelody, despite my dedication to it. :-(

@evernat
Copy link
Member

evernat commented Jun 24, 2021

Generally speaking, you could note that my time to work on that is not infinite. And that it could not be merged if there are known issues or if after many reviews / fixes, review for merge is needed to be sure to avoid blocking regressions for a lot of users. See PR #1012 for example, where fixes of about one line of code out of five has a review, just to scratch the surface. In this PR #966 thanks to @candrews, work and changes were risky and big as the needed reviews. You may look at other major opensource projects, where most issues are not answered for years and closed without explanation, to compare with javamelody.
And I think I will have more time to work on that, starting 10 days from now.

+ "' onclick=\"javascript:return confirm('"
+ getStringForJavascript("confirm_purge_caches") + "');\">");
writeln("<a class='confirm' href='?action=clear_caches" + getCsrfTokenUrlPart()
+ "' data-confirm=\"" + I18N.htmlEncode("confirm_purge_caches", false, false)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The message is not translated anymore here.

writeDirectly(cacheNameEncoded);
writeDirectly("&amp;cacheKey=");
writeDirectly(urlEncode(myKey));
writeDirectly(csrfTokenUrlPart);
writeDirectly("' onclick=\"javascript:return confirm('");
writeDirectly("' data-confirm\"");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

= is missing here

writeDirectly(confirmClearCache);
writeDirectly("');\">");
writeDirectly("\");\">");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

\"); should not be here

write(id);
write("'>");
write("<em><img src='?graph=" + graph + "&width=100&height=50' id='");
write("id" + graph);
write("' alt='graph'/></em>");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

after this change, these images are no longer lazy loaded when onmouseover

});

$$('.deploymentPeriod').invoke("observe", "click", function(event){
showHide('customPeriod');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if this was used, it would have displayed the custom period form instead of the deployment period form

var test = document.createElement('input'); test.type = 'date';
if(test.type === 'text') {
document.customPeriodForm.pattern.value = '';
document.getElementById('customPeriodPattern').style.display='inline';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would have been better to not remove comments on this code

return false;
}
if (periodForm.endDate.value.length == 0) {
alert('Dates are mandatory');
Copy link
Member

@evernat evernat Jul 11, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is no longer translated. Moreover the translations for "Dates are mandatory" are left in properties files for nothing.

@@ -212,62 +210,24 @@ private void writeHtmlHeader(boolean includeSlider, boolean includeCssInline)
if (includeSlider) {
writeln("<script type='text/javascript' src='?resource=slider.js'></script>");
}
writeln("<script type='text/javascript' src='?resource=monitoring.js'></script>");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when includeCssInline above, includes of prototype.js and monitoring.js are missing

writer.write("');location.href='");
writer.write(redirectTo);
writer.write("';</script>");
writeHtmlBegin(writer);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same writeHtmlBegin(writer); is missing in the writeMessage method.

final String endOnClickConfirm = "\">";
writeln("<a class='confirm' href='?action=pause_job&amp;jobId=all"
+ getCsrfTokenUrlPart() + onClickConfirm
+ I18N.htmlEncode(getString("confirm_pause_all_jobs"), false, false)
+ endOnClickConfirm);
writeln("<img src='?resource=control_pause_blue.png' width='18' height='18' alt=\"#Pause_all_jobs#\" /> #Pause_all_jobs#</a>");
writeln("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;");
writeln("<a href='?action=resume_job&amp;jobId=all" + getCsrfTokenUrlPart()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

class='confirm' is missing here

final String onClickConfirm = "' onclick=\"javascript:return confirm('";
final String endOnClickConfirm = "');\">";
final String onClickConfirm = "' data-confirm=\"";
final String endOnClickConfirm = "\">";
writeln("<a href='?action=pause_job&amp;jobId=" + jobInformations.getGlobalJobId()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

class='confirm' is also missing here

writeln("<a href='?action=pause_job&amp;jobId=" + jobInformations.getGlobalJobId()
+ getCsrfTokenUrlPart() + onClickConfirm
+ getStringForJavascript("confirm_pause_job") + endOnClickConfirm);
+ I18N.htmlEncode(getString("confirm_pause_job"), false, false)
+ endOnClickConfirm);
writeln("<img src='?resource=control_pause_blue.png' width='18' height='18' alt=\"#Pause_job#\" title=\"#Pause_job#\" /></a>");
write("</td> <td align='center' class='noPrint'>");
writeln("<a href='?action=resume_job&amp;jobId=" + jobInformations.getGlobalJobId()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

class='confirm' is also missing here

+ getStringForJavascript("ramasse_miette_desactive") + "');return false;\">");
writeln("<a class='alert' href='?part=heaphisto&amp;action=gc" + getCsrfTokenUrlPart()
+ "' data-alert=\""
+ I18N.htmlEncode(getString("ramasse_miette_desactive"), false, false) + "\">");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alert is not displayed instead of calling the action

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

by lack of case in monitoring.js

write("<a href='?action=gc" + getCsrfTokenUrlPart() + "' onclick=\"javascript:alert('"
+ getStringForJavascript("ramasse_miette_desactive") + "');return false;\">");
write("<a class='alert' href='?action=gc" + getCsrfTokenUrlPart() + "' data-alert=\""
+ I18N.htmlEncode(getString("ramasse_miette_desactive"), false, false) + "\">");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alert is not displayed here neither instead of calling the action

evernat added a commit that referenced this pull request Jul 12, 2021
goldyliang pushed a commit to goldyliang/javamelody that referenced this pull request Mar 17, 2022
goldyliang pushed a commit to goldyliang/javamelody that referenced this pull request Mar 17, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants