security.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. /**
  5. * The Security devtool supports the following arguments:
  6. * * Security CSP
  7. * Provides feedback about the current CSP
  8. *
  9. * * Security referrer
  10. * Provides information about the current referrer policy
  11. */
  12. "use strict";
  13. const { Cc, Ci, Cu, CC } = require("chrome");
  14. const l10n = require("gcli/l10n");
  15. const CSP = Cc["@mozilla.org/cspcontext;1"].getService(Ci.nsIContentSecurityPolicy);
  16. const GOOD_IMG_SRC = "chrome://browser/content/gcli_sec_good.svg";
  17. const MOD_IMG_SRC = "chrome://browser/content/gcli_sec_moderate.svg";
  18. const BAD_IMG_SRC = "chrome://browser/content/gcli_sec_bad.svg";
  19. // special handling within policy
  20. const POLICY_REPORT_ONLY = "report-only"
  21. // special handling of directives
  22. const DIR_UPGRADE_INSECURE = "upgrade-insecure-requests";
  23. const DIR_BLOCK_ALL_MIXED_CONTENT = "block-all-mixed-content";
  24. // special handling of sources
  25. const SRC_UNSAFE_INLINE = "'unsafe-inline'";
  26. const SRC_UNSAFE_EVAL = "'unsafe-eval'";
  27. const WILDCARD_MSG = l10n.lookup("securityCSPRemWildCard");
  28. const XSS_WARNING_MSG = l10n.lookup("securityCSPPotentialXSS");
  29. const NO_CSP_ON_PAGE_MSG = l10n.lookup("securityCSPNoCSPOnPage");
  30. const CONTENT_SECURITY_POLICY_MSG = l10n.lookup("securityCSPHeaderOnPage");
  31. const CONTENT_SECURITY_POLICY_REPORT_ONLY_MSG = l10n.lookup("securityCSPROHeaderOnPage");
  32. const NEXT_URI_HEADER = l10n.lookup("securityReferrerNextURI");
  33. const CALCULATED_REFERRER_HEADER = l10n.lookup("securityReferrerCalculatedReferrer");
  34. /* The official names from the W3C Referrer Policy Draft http://www.w3.org/TR/referrer-policy/ */
  35. const REFERRER_POLICY_NAMES = [ "None When Downgrade (default)", "None", "Origin Only", "Origin When Cross-Origin", "Unsafe URL" ];
  36. exports.items = [
  37. {
  38. // --- General Security information
  39. name: "security",
  40. description: l10n.lookup("securityPrivacyDesc"),
  41. manual: l10n.lookup("securityManual")
  42. },
  43. {
  44. // --- CSP specific Security information
  45. item: "command",
  46. runAt: "server",
  47. name: "security csp",
  48. description: l10n.lookup("securityCSPDesc"),
  49. manual: l10n.lookup("securityCSPManual"),
  50. returnType: "securityCSPInfo",
  51. exec: function(args, context) {
  52. var cspJSON = context.environment.document.nodePrincipal.cspJSON;
  53. var cspOBJ = JSON.parse(cspJSON);
  54. var outPolicies = [];
  55. var policies = cspOBJ["csp-policies"];
  56. // loop over all the different policies
  57. for (var csp in policies) {
  58. var curPolicy = policies[csp];
  59. // loop over all the directive-values within that policy
  60. var outDirectives = [];
  61. var outHeader = CONTENT_SECURITY_POLICY_MSG;
  62. for (var dir in curPolicy) {
  63. var curDir = curPolicy[dir];
  64. // when iterating properties within the obj we might also
  65. // encounter the 'report-only' flag, which is not a csp directive.
  66. if (dir === POLICY_REPORT_ONLY) {
  67. outHeader = curPolicy[POLICY_REPORT_ONLY] === true ?
  68. CONTENT_SECURITY_POLICY_REPORT_ONLY_MSG :
  69. CONTENT_SECURITY_POLICY_MSG;
  70. continue;
  71. }
  72. // loop over all the directive-sources within that directive
  73. var outSrcs = [];
  74. // special case handling for the directives
  75. // upgrade-insecure-requests and block-all-mixed-content
  76. // which do not include any srcs
  77. if (dir === DIR_UPGRADE_INSECURE ||
  78. dir === DIR_BLOCK_ALL_MIXED_CONTENT) {
  79. outSrcs.push({
  80. icon: GOOD_IMG_SRC,
  81. src: "", // no src
  82. desc: "" // no description
  83. });
  84. }
  85. for (var src in curDir) {
  86. var curSrc = curDir[src];
  87. // the default icon and descritpion of the directive-src
  88. var outIcon = GOOD_IMG_SRC;
  89. var outDesc = "";
  90. if (curSrc.indexOf("*") > -1) {
  91. outIcon = MOD_IMG_SRC;
  92. outDesc = WILDCARD_MSG;
  93. }
  94. if (curSrc == SRC_UNSAFE_INLINE || curSrc == SRC_UNSAFE_EVAL) {
  95. outIcon = BAD_IMG_SRC;
  96. outDesc = XSS_WARNING_MSG;
  97. }
  98. outSrcs.push({
  99. icon: outIcon,
  100. src: curSrc,
  101. desc: outDesc
  102. });
  103. }
  104. // append info about that directive to the directives array
  105. outDirectives.push({
  106. dirValue: dir,
  107. dirSrc: outSrcs
  108. });
  109. }
  110. // append info about the policy to the policies array
  111. outPolicies.push({
  112. header: outHeader,
  113. directives: outDirectives
  114. });
  115. }
  116. return outPolicies;
  117. }
  118. },
  119. {
  120. item: "converter",
  121. from: "securityCSPInfo",
  122. to: "view",
  123. exec: function(cspInfo, context) {
  124. var url = context.environment.target.url;
  125. if (cspInfo.length == 0) {
  126. return context.createView({
  127. html:
  128. "<table class='gcli-csp-detail' cellspacing='10' valign='top'>" +
  129. " <tr>" +
  130. " <td> <img src='chrome://browser/content/gcli_sec_bad.svg' width='20px' /> </td> " +
  131. " <td>" + NO_CSP_ON_PAGE_MSG + " <b>" + url + "</b></td>" +
  132. " </tr>" +
  133. "</table>"});
  134. }
  135. return context.createView({
  136. html:
  137. "<table class='gcli-csp-detail' cellspacing='10' valign='top'>" +
  138. // iterate all policies
  139. " <tr foreach='csp in ${cspinfo}' >" +
  140. " <td> ${csp.header} <b>" + url + "</b><br/><br/>" +
  141. " <table class='gcli-csp-dir-detail' valign='top'>" +
  142. // >> iterate all directives
  143. " <tr foreach='dir in ${csp.directives}' >" +
  144. " <td valign='top'> ${dir.dirValue} </td>" +
  145. " <td valign='top'>" +
  146. " <table class='gcli-csp-src-detail' valign='top'>" +
  147. // >> >> iterate all srs
  148. " <tr foreach='src in ${dir.dirSrc}' >" +
  149. " <td valign='center' width='20px'> <img src= \"${src.icon}\" width='20px' /> </td> " +
  150. " <td valign='center' width='200px'> ${src.src} </td>" +
  151. " <td valign='center'> ${src.desc} </td>" +
  152. " </tr>" +
  153. " </table>" +
  154. " </td>" +
  155. " </tr>" +
  156. " </table>" +
  157. " </td>" +
  158. " </tr>" +
  159. "</table>",
  160. data: {
  161. cspinfo: cspInfo,
  162. }
  163. });
  164. }
  165. },
  166. {
  167. // --- Referrer Policy specific Security information
  168. item: "command",
  169. runAt: "server",
  170. name: "security referrer",
  171. description: l10n.lookup("securityReferrerPolicyDesc"),
  172. manual: l10n.lookup("securityReferrerPolicyManual"),
  173. returnType: "securityReferrerPolicyInfo",
  174. exec: function(args, context) {
  175. var doc = context.environment.document;
  176. var referrerPolicy = doc.referrerPolicy;
  177. var pageURI = doc.documentURIObject;
  178. var sameDomainReferrer = "";
  179. var otherDomainReferrer = "";
  180. var downgradeReferrer = "";
  181. var otherDowngradeReferrer = "";
  182. var origin = pageURI.prePath;
  183. switch (referrerPolicy) {
  184. case Ci.nsIHttpChannel.REFERRER_POLICY_NO_REFERRER:
  185. // sends no referrer
  186. sameDomainReferrer
  187. = otherDomainReferrer
  188. = downgradeReferrer
  189. = otherDowngradeReferrer
  190. = "(no referrer)";
  191. break;
  192. case Ci.nsIHttpChannel.REFERRER_POLICY_ORIGIN:
  193. // only sends the origin of the referring URL
  194. sameDomainReferrer
  195. = otherDomainReferrer
  196. = downgradeReferrer
  197. = otherDowngradeReferrer
  198. = origin;
  199. break;
  200. case Ci.nsIHttpChannel.REFERRER_POLICY_ORIGIN_WHEN_XORIGIN:
  201. // same as default, but reduced to ORIGIN when cross-origin.
  202. sameDomainReferrer = pageURI.spec;
  203. otherDomainReferrer
  204. = downgradeReferrer
  205. = otherDowngradeReferrer
  206. = origin;
  207. break;
  208. case Ci.nsIHttpChannel.REFERRER_POLICY_UNSAFE_URL:
  209. // always sends the referrer, even on downgrade.
  210. sameDomainReferrer
  211. = otherDomainReferrer
  212. = downgradeReferrer
  213. = otherDowngradeReferrer
  214. = pageURI.spec;
  215. break;
  216. case Ci.nsIHttpChannel.REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE:
  217. // default state, doesn't send referrer from https->http
  218. sameDomainReferrer = otherDomainReferrer = pageURI.spec;
  219. downgradeReferrer = otherDowngradeReferrer = "(no referrer)";
  220. break;
  221. default:
  222. // this is a new referrer policy which we do not know about
  223. sameDomainReferrer
  224. = otherDomainReferrer
  225. = downgradeReferrer
  226. = otherDowngradeReferrer
  227. = "(unknown Referrer Policy)";
  228. break;
  229. }
  230. var sameDomainUri = origin + "/*";
  231. var referrerUrls = [
  232. // add the referrer uri 'referrer' we would send when visiting 'uri'
  233. {
  234. uri: pageURI.scheme+'://example.com/',
  235. referrer: otherDomainReferrer,
  236. description: l10n.lookup('securityReferrerPolicyOtherDomain')},
  237. {
  238. uri: sameDomainUri,
  239. referrer: sameDomainReferrer,
  240. description: l10n.lookup('securityReferrerPolicySameDomain')}
  241. ];
  242. if (pageURI.schemeIs('https')) {
  243. // add the referrer we would send on downgrading http->https
  244. if (sameDomainReferrer != downgradeReferrer) {
  245. referrerUrls.push({
  246. uri: "http://"+pageURI.hostPort+"/*",
  247. referrer: downgradeReferrer,
  248. description:
  249. l10n.lookup('securityReferrerPolicySameDomainDowngrade')
  250. });
  251. }
  252. if (otherDomainReferrer != otherDowngradeReferrer) {
  253. referrerUrls.push({
  254. uri: "http://example.com/",
  255. referrer: otherDowngradeReferrer,
  256. description:
  257. l10n.lookup('securityReferrerPolicyOtherDomainDowngrade')
  258. });
  259. }
  260. }
  261. return {
  262. header: l10n.lookupFormat("securityReferrerPolicyReportHeader",
  263. [pageURI.spec]),
  264. policyName: REFERRER_POLICY_NAMES[referrerPolicy],
  265. urls: referrerUrls
  266. }
  267. }
  268. },
  269. {
  270. item: "converter",
  271. from: "securityReferrerPolicyInfo",
  272. to: "view",
  273. exec: function(referrerPolicyInfo, context) {
  274. return context.createView({
  275. html:
  276. "<div class='gcli-referrer-policy'>" +
  277. " <strong> ${rpi.header} </strong> <br />" +
  278. " ${rpi.policyName} <br />" +
  279. " <table class='gcli-referrer-policy-detail' cellspacing='10' >" +
  280. " <tr>" +
  281. " <th> " + NEXT_URI_HEADER + " </th>" +
  282. " <th> " + CALCULATED_REFERRER_HEADER + " </th>" +
  283. " </tr>" +
  284. // iterate all policies
  285. " <tr foreach='nextURI in ${rpi.urls}' >" +
  286. " <td> ${nextURI.description} (e.g., ${nextURI.uri}) </td>" +
  287. " <td> ${nextURI.referrer} </td>" +
  288. " </tr>" +
  289. " </table>" +
  290. "</div>",
  291. data: {
  292. rpi: referrerPolicyInfo,
  293. }
  294. });
  295. }
  296. }
  297. ];