{"id":156,"date":"2020-08-05T03:53:35","date_gmt":"2020-08-05T10:53:35","guid":{"rendered":"https:\/\/blog.mozilla.org\/attack-and-defense\/?p=156"},"modified":"2020-08-05T03:53:35","modified_gmt":"2020-08-05T10:53:35","slug":"understanding-web-security-checks-in-firefox-part-2","status":"publish","type":"post","link":"https:\/\/blog.mozilla.org\/attack-and-defense\/2020\/08\/05\/understanding-web-security-checks-in-firefox-part-2\/","title":{"rendered":"Understanding Web Security Checks in Firefox (Part 2)"},"content":{"rendered":"<p>&nbsp;<\/p>\n<p>This is the second and final part of a blog post series that explains how Firefox implements Web Security fundamentals, like the <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/Security\/Same-origin_policy\">Same-Origin Policy<\/a> and <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/CSP\">Content-Security-Policy<\/a>. While the <a href=\"https:\/\/blog.mozilla.org\/attack-and-defense\/2020\/06\/10\/understanding-web-security-checks-in-firefox-part-1\/\">first post<\/a> explained Firefox security terminology and theoretical foundations, this second post covers how to log internal security information to the console in a human readable format. Ultimately, we hope to inspire new security research in the area of web security checks and to empower participants in our bug bounty program to do better, deeper work.<\/p>\n<p>Generally, we encourage everyone to do their security testing in <a href=\"https:\/\/www.mozilla.org\/en-US\/firefox\/channel\/desktop\/#nightly\">Firefox Nightly<\/a>. That being said, the logging mechanisms described in this post, work in all versions of Firefox \u2013 from <a href=\"https:\/\/firefox-source-docs.mozilla.org\/setup\/index.html\">self-build<\/a>, to versions of <a href=\"https:\/\/www.mozilla.org\/en-US\/firefox\/channel\/desktop\/#nightly\">Nightly<\/a>, <a href=\"https:\/\/www.mozilla.org\/en-US\/firefox\/channel\/desktop\/\">Beta<\/a>, <a href=\"https:\/\/www.mozilla.org\/en-US\/firefox\/developer\/\">Developer Edition<\/a>, <a href=\"https:\/\/www.mozilla.org\/en-US\/firefox\/new\/\">Release<\/a> and <a href=\"https:\/\/www.mozilla.org\/en-US\/firefox\/enterprise\/\">ESR<\/a> you may have installed locally already.<\/p>\n<h2>Logging Security Internals to the console<\/h2>\n<p>All Firefox versions ship with a <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Mozilla\/Developer_guide\/Gecko_Logging\">logging framework<\/a> that allows one to inspect <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Mozilla\/Gecko\">Gecko&#8217;s<\/a> (Firefox\u2019 rendering engine) internals. In general, logging Firefox internals is as easy as defining an environment variable called <code>MOZ_LOG<\/code>. When testing on mobile, the document <a href=\"https:\/\/firefox-source-docs.mozilla.org\/mobile\/android\/geckoview\/consumer\/automation.html\">Configuring GeckoView<\/a> describes and guides you through defining environment variables in GeckoView\u2019s runtime environment. For printing web security checks we simply have to enable the logger named <code><a href=\"https:\/\/searchfox.org\/mozilla-central\/source\/dom\/security\/nsContentSecurityManager.cpp#49\">\"CSMLog\"<\/a><\/code>. You can also set <code><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Mozilla\/Developer_guide\/Gecko_Logging#Enabling_Logging\">MOZ_LOG_FILE<\/a><\/code> if you want to write into a log file.<\/p>\n<p>Defining <code>MOZ_LOG=\"CSMLog:5\"<\/code> as an environment variable will print all security checks to the console, where the digit 5 indicates the highest log-level (<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Mozilla\/Developer_guide\/Gecko_Logging\">Verbose<\/a>) which naturally prints a lot of debugging information but in turn allows debugging program flow.<\/p>\n<h2>Understanding Security Load Information<\/h2>\n<p>Here is a log example when defining <code>CSMLog:5<\/code> and opening <a href=\"http:\/\/example.com\">https:\/\/example.com<\/a> in a new tab. For the sake of simplicity we removed line prefixes like <code>[Parent 361301: Main Thread]<\/code> which provide additional information around process type (parent\/child), process id (pid) and the thread in which the logging occurred. These <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Mozilla\/Developer_guide\/Gecko_Logging#Enabling_Logging\">prefixes can also be omitted<\/a> by appending <code>\",raw\"<\/code> to the <code>MOZ_LOG<\/code> value.<\/p>\n<table>\n<tbody>\n<tr>\n<td>\n<pre>V\/CSMLog doContentSecurityCheck:\r\nV\/CSMLog \u00a0 - <b>channelURI<\/b>: https:\/\/example.com\/\r\nV\/CSMLog \u00a0 - <b>httpMethod<\/b>: GET\r\nD\/CSMLog \u00a0 - <b>loadingPrincipal<\/b>: nullptr\r\nD\/CSMLog \u00a0 - <b>triggeringPrincipal<\/b>: SystemPrincipal\r\nD\/CSMLog \u00a0 - <b>principalToInherit<\/b>: NullPrincipal\r\nV\/CSMLog \u00a0 - <b>redirectChain<\/b>:\r\nV\/CSMLog \u00a0 - <b>internalContentPolicyType<\/b>: TYPE_DOCUMENT\r\nV\/CSMLog \u00a0 - <b>externalContentPolicyType<\/b>: TYPE_DOCUMENT\r\nV\/CSMLog \u00a0 - <b>upgradeInsecureRequests<\/b>: false\r\nV\/CSMLog \u00a0 - <b>initialSecurityChecksDone<\/b>: false\r\nV\/CSMLog \u00a0 - <b>allowDeprecatedSystemRequests<\/b>: false\r\nD\/CSMLog \u00a0 - <b>CSP<\/b>:\r\nV\/CSMLog \u00a0 - <b>securityFlags<\/b>:\r\nV\/CSMLog \u00a0\u00a0\u00a0 - SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Listing 1: Firefox Security Log (<code>CSMLog:5<\/code>) when opening <a href=\"http:\/\/example.com\">https:\/\/example.com<\/a> in a new tab.<\/p>\n<p>As of Firefox 80, every logged Web Security Check appears in the format from Listing 1. At the beginning of each line you see <code>CSMLog<\/code> which is the name of our logger and D\/V are short for Debug\/Verbose, which indicate the log level (4 is Debug, 5 is Verbose). The output format after this prefix is valid YAML and should be easy to parse automatically. These blocks of attributes are surrounded by <b>#DebugDoContentSecurityCheck Begin <\/b>and <b>End<\/b> for each and every outgoing request, which corresponds to the function name <a href=\"https:\/\/searchfox.org\/mozilla-central\/rev\/82c04b9cad5b98bdf682bd477f2b1e3071b004ad\/dom\/security\/nsContentSecurityManager.cpp#1017\">doContentSecurityCheck<\/a> in the SecurityManager. This function contains all available information of the current security context, before a request is sent over the wire. Naturally, this does not include the security checks that can only happen after the response is received (e.g., <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Headers\/X-Frame-Options\">X-Frame-Options<\/a>, <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Headers\/X-Content-Type-Options\">X-Content-Type-Options<\/a>, etc.).<\/p>\n<p>Most of the information below is readily available through the <a href=\"https:\/\/searchfox.org\/mozilla-central\/source\/netwerk\/base\/nsILoadInfo.idl\">nsILoadinfo<\/a> object that corresponds to the request:<\/p>\n<p><code><b>channelURI<\/b><\/code><br \/>\nThe URI about to be loaded and evaluated within this security check.<\/p>\n<p><code><b>httpMethod<\/b><\/code> (optional)<br \/>\nIndicates the <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Methods\">HTTP request methods<\/a> like e.g., GET, HEAD or POST and hence is only available for HTTP requests.<\/p>\n<p><code><b>loadingPrincipal<\/b><\/code><br \/>\nIn general, the <a href=\"https:\/\/searchfox.org\/mozilla-central\/rev\/82c04b9cad5b98bdf682bd477f2b1e3071b004ad\/netwerk\/base\/nsILoadInfo.idl#254\">loadingPrincipa<\/a>l reflects the security context (<a href=\"https:\/\/blog.mozilla.org\/attack-and-defense\/2020\/06\/10\/understanding-web-security-checks-in-firefox-part-1\/\">the Principal<\/a>) where the result of this resource load will be used. In case of an image load for example, this would be the security context (ContentPrincipal) of the loading document. Since this is a top-level load, the loadingPrincipal is null because the result of the load is a new document.<\/p>\n<p><code><b>triggeringPrincipal<\/b><\/code><br \/>\nThe security context (<a href=\"https:\/\/blog.mozilla.org\/attack-and-defense\/2020\/06\/10\/understanding-web-security-checks-in-firefox-part-1\/\">reflected through a Principal<\/a>) which triggered this load. For almost all subresource loads, the <a href=\"https:\/\/searchfox.org\/mozilla-central\/rev\/82c04b9cad5b98bdf682bd477f2b1e3071b004ad\/netwerk\/base\/nsILoadInfo.idl#304\">triggeringPrincipal<\/a> and the <a href=\"https:\/\/searchfox.org\/mozilla-central\/rev\/82c04b9cad5b98bdf682bd477f2b1e3071b004ad\/netwerk\/base\/nsILoadInfo.idl#254\">loadingPrincipal<\/a> are identical. Since the user entered <a href=\"http:\/\/example.com\">https:\/\/example.com<\/a> in the URL-Bar, it is a user-triggered action which in Firefox is equivalent to a load triggered by the System and hence is using a SystemPrincipal as the triggeringPrincipal. For the sake of completeness, imagine a cross-origin CSS file which loads a background image. Then the triggeringPrincipal for that image load would be the security context (ContentPrincipal) of the CSS, but the loadingPrincipal would be the security context (ContentPrincipal) of the document where the image load will be used.<\/p>\n<p><code><b>principalToInherit<\/b><\/code><br \/>\nThe <a href=\"https:\/\/searchfox.org\/mozilla-central\/rev\/82c04b9cad5b98bdf682bd477f2b1e3071b004ad\/netwerk\/base\/nsILoadInfo.idl#320\">principalToInherit<\/a> is only relevant to loads of type document (top-level loads) and type subdocument (e.g., iframe loads) and indicates the principal that will be inherited, e.g., when loading a data URI.<\/p>\n<p><code><b>redirectChain<\/b><\/code><b><br \/>\n<\/b>In case a load encounters a redirect (e.g. a<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Redirections\"> 302 server side redirect<\/a>) then the RedirectChain contains all Principals (serialized into origin URI strings) of all the redirects this load went through.<\/p>\n<p><code><b>internalContentPolicyType\/externalContentPolicyType<\/b><\/code><b><br \/>\n<\/b>Indicates the (internal and external) content policy type of the load. In that particular case, the load was of <a href=\"https:\/\/searchfox.org\/mozilla-central\/rev\/82c04b9cad5b98bdf682bd477f2b1e3071b004ad\/dom\/base\/nsIContentPolicy.idl#90\">TYPE_DOCUMENT<\/a>. The reason there is an internal and an external type is because Firefox needs to enforce different security mappings. For example, the separation of different script types allows precise mapping to e.g. CSP directives.<\/p>\n<p><code><b>upgradeInsecureRequests<\/b><\/code><b><br \/>\n<\/b>Indicates whether the request needs to be upgraded from HTTP to HTTPS before it hits the network due to the CSP directive <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Headers\/Upgrade-Insecure-Requests\">upgrade-insecure-requests<\/a>.<\/p>\n<p><code><b>initialSecurityChecksDone<\/b><\/code><b><br \/>\n<\/b>Whenever the ContentSecurityManager performs security checks the first time for a channel, then this bit gets flipped indicating that initial security checks on that channel have been completed. In turn, this flag causes certain security checks, like e.g. <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/CORS\">CORS<\/a>, to be bypassed after a redirect.<\/p>\n<p><code><b>allowDeprecatedSystemRequests<\/b><\/code><br \/>\nIn one of our <a href=\"https:\/\/blog.mozilla.org\/attack-and-defense\/2020\/07\/07\/hardening-firefox-against-injection-attacks-the-technical-details\/\">hardening efforts<\/a>, we started to disallow web requests in system privileged contexts, when the triggeringPrincipal is of type SystemPrincipal (see <code><a href=\"https:\/\/searchfox.org\/mozilla-central\/rev\/1b95a0179507a4dc7d4b0c94c2df420dc1a72885\/dom\/security\/nsContentSecurityManager.cpp#821\">CheckAllowLoadInSystemPrivilegedContext()<\/a><\/code>). However, there are certain system requests where we allow that temporarily, e.g., for <a href=\"https:\/\/searchfox.org\/mozilla-central\/rev\/9b282b34b5aa0f836beb735656c55efb2cc4c617\/security\/manager\/ssl\/nsNSSCallbacks.cpp#275\">OCSP requests<\/a>.<\/p>\n<p><code><b>CSP<\/b><\/code><br \/>\nThe <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/CSP\">Content Security Policy<\/a> that needs to be enforced for this request. If there is no CSP to enforce, then the value for this field remains empty.<\/p>\n<p><code><b>securityFlags<\/b><\/code><br \/>\nThe <a href=\"https:\/\/searchfox.org\/mozilla-central\/rev\/1b95a0179507a4dc7d4b0c94c2df420dc1a72885\/netwerk\/base\/nsILoadInfo.idl#71\">securityFlags<\/a> indicate what kind of security checks need to be performed for that channel. For example, whether to enforce the same-origin-policy or whether this load requires <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/CORS\">CORS<\/a>.<\/p>\n<h2>Analyzing and Finding Security Bugs with Logging<\/h2>\n<p>Now that we know all the entries in a web security log, let\u2019s dive a little deeper and investigate a historical bug and how it could have been found using the discussed logging capabilities. We will be looking at <a href=\"https:\/\/www.mozilla.org\/en-US\/security\/advisories\/mfsa2019-34\/#CVE-2019-17000\">CVE-2019-17000<\/a>, a limited CSP bypass from October 2019 that we fixed in Firefox 70. A Proof of Concept could look a bit like this:<\/p>\n<table>\n<tbody>\n<tr>\n<td>\n<pre><span style=\"color: #800000;\">&lt;meta<\/span> <span style=\"color: #ff0000;\">http-equiv<\/span><span style=\"color: #000000;\">=<\/span><span style=\"color: #0000ff;\">\"Content-Security-Policy\"<\/span>\r\n      <span style=\"color: #ff0000;\">content<\/span><span style=\"color: #000000;\">=<\/span><span style=\"color: #0000ff;\">\"default-src 'self'; object-src data:; img-src 'none';\"<\/span><span style=\"color: #800000;\">\/&gt;<\/span>\r\n<span style=\"color: #800000;\">&lt;body&gt;<\/span>\r\n<span style=\"color: #000000;\">  The following object element is allowed.<\/span>\r\n  <span style=\"color: #800000;\">&lt;object<\/span> <span style=\"color: #ff0000;\">data<\/span><span style=\"color: #000000;\">=<\/span><span style=\"color: #0000ff;\">'data:text\/html,<\/span><span style=\"color: #cd3131;\">&lt;<\/span><span style=\"color: #0000ff;\">p&gt;Object element has an image:<\/span><span style=\"color: #cd3131;\">&lt;<\/span><span style=\"color: #0000ff;\">br&gt;<\/span>\r\n  <span style=\"color: #cd3131;\">&lt;<\/span><span style=\"color: #0000ff;\">img src=\"<span style=\"color: #1155cc;\"><u>https:\/\/freddyb.neocities.org\/danger.jpg<\/u><\/span><span style=\"color: #0000ff;\">\"<\/span>\r\n       <span style=\"color: #0000ff;\">alt=\"This image should not load\"\/&gt;<\/span><span style=\"color: #cd3131;\">&lt;<\/span><span style=\"color: #0000ff;\">br&gt;<\/span>\r\n   <span style=\"color: #0000ff;\">This text is underneath the image.'<\/span><span style=\"color: #800000;\">&gt;<\/span>\r\n<span style=\"color: #800000;\">  &lt;\/object&gt;<\/span>\r\n<span style=\"color: #800000;\">&lt;\/body&gt;<\/span><\/span><\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Listing 2: Document defining a CSP blocking all images and loading an &lt;object&gt; tag with a data: URI.<\/p>\n<p>The document in Listing 2 comes with a Content-Security-Policy that allows loading object elements which point to a data URL (object-src data:), but denies all image loads (img-src &#8216;none&#8217;). A browser needs to perform various security checks to completely load this document: First, we\u2019re loading the top level document in a new tab, which is allowed. Then, we adjust the document\u2019s CSP given the <code>&lt;meta&gt;<\/code> element and load the <code>&lt;object&gt;<\/code> element according to the CSP (allowed in object-src). Given it\u2019s data URL, the <code>&lt;object<\/code>&gt; element is cross-origin (i.e., loaded using a <a href=\"https:\/\/blog.mozilla.org\/attack-and-defense\/2020\/06\/10\/understanding-web-security-checks-in-firefox-part-1\/\">NullPrincipal<\/a>). Therefore, the inner <code>&lt;img&gt;<\/code> element needs to be loaded using a different, unique origin. However, the image load should still be forbidden based on the img-src &#8216;none&#8217; directive of the <i>parent <\/i>document!<\/p>\n<p>Let\u2019s take a closer look at just the image request when logging in an unaffected version of Firefox:<\/p>\n<table>\n<tbody>\n<tr>\n<td>\n<pre>doContentSecurityCheck:\r\n - <b>channelURI<\/b>: https:\/\/freddyb.neocities.org\/danger.jpg\r\n - <b>httpMethod<\/b>: GET\r\n - <b>loadingPrincipal<\/b>: NullPrincipal\r\n - <b>triggeringPrincipal<\/b>: NullPrincipal\r\n - <b>principalToInherit<\/b>: nullptr\r\n - <b>redirectChain<\/b>:\r\n - <b>internalContentPolicyType<\/b>: TYPE_INTERNAL_IMAGE\r\n - <b>externalContentPolicyType<\/b>: TYPE_IMAGE\r\n - <b>upgradeInsecureRequests<\/b>: true\r\n - <b>initialSecurityChecksDone<\/b>: false\r\n - <b>allowDeprecatedSystemRequests<\/b>: false\r\n - <b>CSP<\/b>:\r\n    - default-src 'self'; object-src data:; img-src 'none'\r\n - <b>securityFlags<\/b>:\r\n   - SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT\r\n   - SEC_ALLOW_CHROME<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Listing 3: The request is loaded into a new Security Context (using a NullPrincipal), but the CSP is inherited.<\/p>\n<p>But here is what it looked like in the vulnerable Firefox version 69:<\/p>\n<table>\n<tbody>\n<tr>\n<td><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-157\" src=\"http:\/\/blog.mozilla.org\/attack-and-defense\/files\/2020\/08\/csp-bypass-example.png\" alt=\"Screenshot of the page opened in a vulnerable version of Firefox 69.\" width=\"594\" height=\"156\" srcset=\"https:\/\/blog.mozilla.org\/attack-and-defense\/files\/2020\/08\/csp-bypass-example.png 594w, https:\/\/blog.mozilla.org\/attack-and-defense\/files\/2020\/08\/csp-bypass-example-300x79.png 300w\" sizes=\"(max-width: 594px) 100vw, 594px\" \/><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Listing 4: Screenshot of the page opened in a vulnerable version of Firefox 69. Photo by<a href=\"https:\/\/unsplash.com\/@mikael_seegen\"> Mikael Seegen<\/a>.<\/p>\n<p>So, what happened here &#8211; why did the image load?<\/p>\n<p>We can investigate the erroneous behavior using our logging. Here\u2019s a listing for the very same image request from Firefox 69:<\/p>\n<table>\n<tbody>\n<tr>\n<td>\n<pre>doContentSecurityCheck:\r\n - <b>channelURI<\/b>: https:\/\/freddyb.neocities.org\/danger.jpg\r\n - <b>httpMethod<\/b>: GET\r\n - <b>loadingPrincipal<\/b>: NullPrincipal\r\n - <b>triggeringPrincipal<\/b>: NullPrincipal\r\n - <b>principalToInherit<\/b>: nullptr\r\n - <b>redirectChain<\/b>:\r\n - <b>internalContentPolicyType<\/b>: TYPE_INTERNAL_IMAGE\r\n - <b>externalContentPolicyType<\/b>: TYPE_IMAGE\r\n - <b>upgradeInsecureRequests<\/b>: true\r\n - <b>initialSecurityChecksDone<\/b>: false\r\n - <b>CSP<\/b>:\r\n - <b>securityFlags<\/b>:\r\n   - SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT\r\n   - SEC_ALLOW_CHROME<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Listing 5: The very same request as in Listing 3, but logged using Firefox 69.<\/p>\n<p>Can you spot the difference?<\/p>\n<p>In the vulnerable case (Listing 5), the security check was not aware of an effective CSP. Even though the <code>&lt;object&gt;<\/code>\u2019s content does not inherit the origin of the page (it\u2019s loaded with a data: URL after all) &#8211; it should inherit the CSP of the document.<\/p>\n<p>An attacker could use a CSP bypass like this and target users on web pages that are susceptible to XSS or content injections. However, this bug was identified in a previous version of Firefox and has been fixed for all of our users since.<\/p>\n<p>To summarize, using the provided logging mechanism allows us to effectively detect security problems by visual inspection. One could take it even further and generate graph structures for nested page loads. Using these graphs to observe where the security context (e.g., the CSP) changes can be a very powerful tool for runtime security analysis.<\/p>\n<h2>Going Forward<\/h2>\n<p>We have explained how to enable logging mechanisms within Firefox which allows for visual inspection of every web security check performed. We would like to point out that finding security flaws might be eligible for a<a href=\"https:\/\/www.mozilla.org\/en-US\/security\/client-bug-bounty\/\"> bug bounty<\/a>. Finally, we hope the provided instructions foster security research and in turn allow researchers, bug bounty hunters and generally everyone interested in web security to contribute to Mozilla and the Security of the Open Web.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>&nbsp; This is the second and final part of a blog post series that explains how Firefox implements Web Security fundamentals, like the Same-Origin Policy and Content-Security-Policy. While the first &hellip; <a class=\"go\" href=\"https:\/\/blog.mozilla.org\/attack-and-defense\/2020\/08\/05\/understanding-web-security-checks-in-firefox-part-2\/\">Read more<\/a><\/p>\n","protected":false},"author":405,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[449525],"tags":[],"coauthors":[280726,280776],"_links":{"self":[{"href":"https:\/\/blog.mozilla.org\/attack-and-defense\/wp-json\/wp\/v2\/posts\/156"}],"collection":[{"href":"https:\/\/blog.mozilla.org\/attack-and-defense\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.mozilla.org\/attack-and-defense\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/attack-and-defense\/wp-json\/wp\/v2\/users\/405"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/attack-and-defense\/wp-json\/wp\/v2\/comments?post=156"}],"version-history":[{"count":0,"href":"https:\/\/blog.mozilla.org\/attack-and-defense\/wp-json\/wp\/v2\/posts\/156\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.mozilla.org\/attack-and-defense\/wp-json\/wp\/v2\/media?parent=156"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.mozilla.org\/attack-and-defense\/wp-json\/wp\/v2\/categories?post=156"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.mozilla.org\/attack-and-defense\/wp-json\/wp\/v2\/tags?post=156"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/blog.mozilla.org\/attack-and-defense\/wp-json\/wp\/v2\/coauthors?post=156"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}