About HTTP header
When a browser opens a file or page on the web, the browser makes HTTP request as shown below and sends it to the Web server.
GET HTTP/2
scheme: https
host: alvine.org
filename: /
          The web server responds to this by adding the response body (data of the page body) to the HTTP response header as shown below. It is case-insensitive.
HTTP/2 200 OK
alt-svc: h3=":443"; ma=2592000
cache-control: max-age=15768000
content-encoding: gzip
content-security-policy: default-src 'self'; frame-ancestors 'none';
content-type: text/html; charset=utf-8
cross-origin-embedder-policy: require-corp
cross-origin-opener-policy: same-origin
cross-origin-resource-policy: same-origin
etag: "d8uywr2ck2s594x-gzip"
last-modified: Tue, 01 Apr 2025 03:05:00 GMT
permissions-policy browsing-topics=(),interest-cohort=(),join-ad-interest-group=(),run-ad-auction=(),attribution-reporting=()
referrer-policy: strict-origin-when-cross-origin
server: Caddy
strict-transport-security: max-age=15768000;
vary: Accept-Encoding
x-content-type-options: nosniff
x-frame-options: DENY
content-length: 3442
date: Tue, 01 Apr 2025 12:34:19 GMT
          The content of the response header can be modified by the web server administrator, and although many sites leave it at the default of the web server application, it can contain important information that is useful to the user. I would like to introduce what I consider to be particularly important.
Security
Cross-Origin- or something like that.
The word “security” sounds exaggerated, but it is all up to the browser to decide how to handle the response, so it is not a matter of setting this much and you are absolutely safe. It is necessary to understand that this is essentially just a “request” from the server.
Content-Security-Policy (CSP)
Content-Security-Policy: default-src 'self'; frame-ancestors 'none';
          Header to restrict loading of third-party elements, useful for preventing XSS (cross-site scripting).
If default-src 'self' is set, elements not
          hosted on the same host as the page (web fonts, embedded SNS
          or share button, etc.) are blocked, as well as inline
          <style> and <script>
          elements. Most websites will be rendered useless, and you
          rarely see a site that uses only self.
Small personal web sites can easily implement it, but if they don’t do dynamic page generation and have no way to introduce XSS, like this site, it’s not worth it.
The well-known x-frame-options: DENY, which
          prevents clickjacking, has already been deprecated and its
          function has been replaced by
          frame-ancestors ‘none’.
CSP is a very deep feature, but it is far beyond my skill.
          For now, it might be a good idea to set
          default-src.
Cross-Origin-Resource-Policy (CORP)
Cross-Origin-Resource-Policy: same-origin
          Restrict loading of this site’s resources from another
          origin (another site). The default is
          cross-origin, which allows requests from any
          origin to load resources. If it is set to
          same-origin or same-site, then
          resources cannot be loaded directly from other sites. However,
          since blocking loading is a browser-side function, it does not
          necessarily mean that the response body will not be sent.
Cross-Origin-Embedder-Policy (COEP)
Cross-Origin-Embedder-Policy: require-corp
          Restrict resources other than the specified origin from
          being loaded on this site. The default is
          unsafe-none, in which case cross-origin resources
          can be loaded without explicit permission in CORP. If set to
          require-corp, it will block reading of any origin
          other than the one explicitly specified in CORP.
Cross-Origin-Opener-Policy (COOP)
Cross-Origin-Opener-Policy: same-origin
          Restrict the site from sharing a browsing context with
          another origin. The default is unsafe-none, which
          means that when another origin is opened from this site, the
          opened origin can control the parent window using JavaScript’s
          window.opener. If same-origin is
          used, the browsing context is not shared between origins, so
          they cannot communicate with each other. It is better to set
          same-origin when there is no need to be
          controlled by other sites.
same-origin-allow-popups is used for kind of a
          payment required services.
Strict-Transport-Security (HSTS)
Strict-Transport-Security: max-age=15768000;
          Forces the browser to redirect to HTTPS when it sends
          request over HTTP. The redirection to HTTPS for this site will
          be in effect for the specified number of seconds. Common
          examples are max-age=15768000 for half a year and
          max-age=31536000 for one year. However, it is
          meaningless if it is not cached in the browser. So no matter
          how long max-age is set, it is meaningless for the first
          access or access in secret mode.
X-Content-Type-Options
X-Content-Type-Options nosniff
          Prevent the browser from sniffing the MIME type of a file.
Headers beginning with X- are either private,
          non-standardized headers, or were once non-standardized but
          are now standardized. The latter is the case. To begin with,
          starting a private header with X- has already
          been deprecated1.
Privacy
Permissions-Policy
Permissions-Policy: browsing-topics=(), interest-cohort=(), join-ad-interest-group=(), run-ad-auction=(), attribution-reporting=()
          This is the core of the “kind HTTP header” that I wanted to convey in this article.
Permissions-Policy is a header that restricts the use of location information and cameras from the website side, but this is not included in this article because the default browser setting should ask for permission and such a setting is not used for personal sites. There is a more important setting than that. Opting-out of Google’s privacy sandbox.
Privacy Sandbox
Privacy Snadbox is the technology to track users “on the device side, not on the server side” by Google, which has finally been closed to the use of third-party cookies as a result of legal restrictions. The name “sandbox” seems to have been given to this technology, which is currently under development.
All of this can only be described as EVIL. Even if your site is being served by Google’s ads, you should disable them.
There is a way to opt out through browser settings, but they no longer make any attempt to hide their intent to deceive those with little concern for security or privacy. Some features can be disabled (at least for this site) via server-side response headers, so let’s disable them for the good of all humankinnd.
Topics API
Permissions-Policy: browsing-topics=()
          The Topics API is a means of tracking users across sites, replacing third-party cookies. Google got flammed worldwidely when it announced FLoC (Federated Learning of Cohorts), a system for grouping users by preferences, and the Topics API seems to be the successor of FLoC. It allows browsers to list and store categories of interest based on the user’s browsing history, and allows the top five categories to be browsed upon request from the website side. However, there is a 5% chance that a random category will be returned.
You can disable the viewer’s browsers to analize contents
          (at least on your site) by setting
          browsing-topics=()2.
FLoC
Permissions-Policy: interest-cohort=()
          interest-cohort is FLoC as explained above. It
          has been succeeded to the Topics API yet you can opt it out
          with interest-cohort=() just in case.
Protected Audience API
Permissions-Policy: join-ad-interest-group=(), run-ad-auction=()
          The Protected Audience API is a system that divides users with common interests into the Interest Groups in advance and run auctions for advertising on their devices. It was originally developed under the name FLEDGE (First “Locally-Executed Decision over Groups” Experiment), but it was renamed “Protected Audience” in 20233.
The target audience is “users who have visited a company’s website in the past,” and the purpose is to give the company an opportunity to remarket to these users.
You can disable adding browsers to interest groups with
          join-ad-interest-group=(). You can disable the
          ability to run auctions with run-ad-auction=(),
          but this may not be relevant if you are not loading ad
          scripts. However, it was not clear to me what data is used to
          add the ads to the interest group. (This seems to be similar
          to the Topics API, but unclear.)
Attribution Reporting API
Permissions-Policy: attribution-reporting=()
          The Attribution Reporting API is a system that allows browsers to send the results of measurement of “when an ad view led to a purchase” to the advertising platform later. It seems completely irrelevant to sites that do not use any ads, such as this site. Although Google is implying that they are going to use for purposes other than advertising in the future4, so it may be a good idea to disable it from now5.
Referrer-Policy
Referrer-Policy: strict-origin-when-cross-origin
          Restrict the referer sent in the request.
Basically, at least between the same origin, sending full URL referer makes it easy to inspect logs, and it is acceptable to send only the domain name to external origins. However, you do not want to send anything from an HTTPS origin to an HTTP origin at all.
In such a case, setting no-referrer is not
          proper because it makes it difficult to inspect requests even
          between the same origin. The best choice is
          strict-origin-when-cross-origin. This is the
          default setting for almost all browsers, including Chrome and
          Firefox.
Reducing network traffic
Cache-Control
Cache-Control: max-age=15768000
          Browsers do not send all HTTP requests, but may create
          responses from caches stored in themselves. By using
          max-age to inform browsers how long the response
          can be reused, it is possible to reduce the extra traffic load
          on the client.
There is no need to worry that users will not be notified
          of site updates even if max-age is set to a
          longer value. The browser judges whether the response body it
          receives is the same as the one in its cache based on the
          values of last-modified and etag in
          the response header, and returns the status code
          304 Not Modified if they are the same, and
          creates a response body from its cache. If so, it returns the
          status code 304 Not Modified and creates a
          response body from the cache. If you find many
          304s in the server logs, you should set a longer
          cache period.
In addition, modern browsers are smart enough to think that
          a site that has not been updated in a year is unlikely to be
          updated again, so they sometimes reuse caches that are more
          than a year old from last-modified and have long
          passed their max-age. This is called a “heuristic
          cache”.
Troubleshooting
Now, I have introduced a fairly strict configuration method, but strict settings sometimes impair convenience.
I would like to show some actual problems caused by HTTP header settings.
SVG turns to be a black
This is the favicon of this site. You’ve seen it right?
One day a while after setting CSP. I suddenly wondered, “Is the favicon displayed properly?” and I opened them in my browser.
All of them were displayed correctly but only
          favicon.svg was displayed as a black square.
At first I thought that the dark mode of the browser might be doing something wrong, but there was no probrem with that. I finally found the cause by downloading and opening the file with a text editor.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
    version="1.1"
    id="svg1"
    width="256.00003"
    height="256.00003"
    viewBox="0 0 256.00003 256.00003"
    xmlns="http://www.w3.org/2000/svg"
    xmlns:svg="http://www.w3.org/2000/svg">
    <style id="style1">
        path {
            fill: #000;
        }
        @media (prefers-color-scheme: dark) {
            path {
                fill: #fff;
            }
        }
    </style>
    <defs id="defs1" />
    <rect
        style=""
        id="rect1"
        width="256"
        height="256"
        x="0"
        y="0" />
    <path
        style=""
        d="M 0,127.99999 (...) "
        id="path3" />
</svg>The <rect> and <path>
          styles are completely missing. (I wonder why style1 is still
          there. It doesn’t change color even in dark mode, so I
          actually don’t need it.)
I solved the problem by returning
          Content-Security-Policy: style-src 'unsafe-inline';
          only for requests for image/svg+xml.
base64 image does not show up
One more thing related to CSP. There’s a base64-encoded
          image on some page on this site, but it was not shown with the
          CSP set to default-src: 'self'. To display it, I
          had to specify the scheme by adding
          img-src 'self' data:;
Twitter OGP
In this site, illustration pages are set up with metadata for OGP (Open Graph Protocol), to share on SNS (especially Twitter). It makes possible to “embedding the webpage in Twitter”.
          Example of OGP
However, for this site, there was a problem that only the thumbnail images were not loaded even though the metadata of the articles were loaded.
          The official OGP Validator was ended, so checking at the post page.
The thumbnails on this site are 160x160, which is much
          smaller than the usual OGP images (often 1200x630), so I
          thought that it might be running afoul of the minimum size,
          but could not solve it6. I left it for
          a while because it was troublesome, but then I noticed that it
          could be a CSP problem, and tried setting
          Cross-Origin-Resource-Policy: cross-origin to the
          directory for thumbnails, and they were displayed.
          Thumbnail is shown properly
Websites I reffered
Specific sources are noted in footnotes.
HTTP header - MDN Web Docs Glossary: Definitions of Web-related terms | MDN
閲覧履歴を元に興味・関心をブラウザが推測して広告主と共有する機能など、プライバシーサンドボックスに含まれるAPIを段階的に有効化していくとGoogleが発表 - GIGAZINE
RFC 6648 - Deprecating the “X-” Prefix and Similar Constructs in Application Protocols↩︎
You can opt out of topic calculation for specific pages on your site by including the
Permissions-Policy: browsing-topics=()Permissions-Policy header on a page to prevent topics calculation for all users on that page only. Subsequent visits to other pages on your site won’t be affected: if you set a policy to block the Topics API on one page, this won’t affect other pages.Note: In the future, the Attribution Reporting API may serve use cases that are not related to advertising.
– Attribution Reporting for Web overview | Privacy Sandbox↩︎
A site can disable the Attribution Reporting API for all parties, including scripts with top-level access, by sending the HTTP response header:
Permissions-Policy: attribution-reporting=()I couldn’t find any limitations on the size of OGP image on the Twitter’s document. | Cards markup | Docs | Twitter Developer Platform↩︎