Abstract
This document introduces a new link tag to specify a signature in HTML documents based on OpenPGP. It also describes how to present the signature information to users reading the document and how to verify it.
Motivation
When a user fetches an HTML document via the HTTPS protocol from a given site, the user can trust that the site is legitimate by checking the TLS certificate and follow the chain until a trusted CA. However, losing the DNS record of the site would cause all content to lose the trust that it had originally, even if the content is copied verbatim elsewhere.
A mirrored copy cannot be trusted unless the author controls the mirror server as well.
Signing the HTML document itself would allow users to verify that the content is legitimate and has not been tampered with, regardless of the transport mechanism used to deliver it to the user.
The OpenPGP specification RFC-9580 describes an standard on how to sign and verify signatures and several implementations are widely available to users, so it will be used as the signature format.
Introduction
An OpenPGP signature is added to an HTML document by first including a
link tag in the head section with the following
three mandatory attributes:
- The
relattribute must be set tosignature. - The
typeattribute must be set to the MIME type of the OpenPGP signature file which isapplication/pgp-signature. - The
hrefattribute must be set to the location of the signature file.
Multiple signatures can be added by including multiple link
tags in the head. All signature tags must be added to the HTML document
before the signatures are created. The signature files are then computed
from the HTML document and placed in their respective files as described by
the href attribute.
Example with GnuPG
To add an OpenPGP signature to an index.html HTML
document using GnuPG:
- Include a
linktag in the head with the attributerel="signature"as follows:<link rel="signature" type="application/pgp-signature" href="index.html.sig">
- Sign the HTML document and generate a detached signature with the
specified name. Example with GnuPG:
$ gpg --output index.html.sig --detach-sig index.html
- Download both the HTML and signature files then verify that the
signature matches. Example with GnuPG:
$ gpg --verify index.html.sig index.html
This HTML document is also signed following the above steps.
Limitations
The signature only covers the HTML file, not any external resource that may be referenced such as CSS, JS, images, fonts or documents in iframes. Those resources could be altered in such a way that the content of the document may change.
A simple example can be build with a style.css like so:
.hide { display: none; }
And a segment of index.html that hides content when the CSS
file is loaded, changing the meaning of the sentence:
I <span class=hide>don't</span> accept the contract.
Similarly, CSS media rules or JavaScript code may cause elements to change causing the meaning to change depending on the user reading the document or other factors.
Authors should not include any additional resources in a signed HTML file. They won't be loaded when a user requests to see the HTML signed document only.
Considerations
The current model assumes that authors won't create misleading documents, as it would be possible to change the meaning of the document even without including external resources, using embedded JS or CSS rules.
It is not enough to verify that a signature is valid, the key must be trusted by the user reading the document. Otherwise an actor could simply sign a changed document with its own key and pretend it is the original author. Users are expected to know how the web of trust works.
An attacker that is able to control the content of the HTML document (for example transmitted over HTTP) could simply remove any signatures and tamper the document. We assume that trust cannot be established unless a valid signature is present.
The type of the signature is exclusively determined by the
type attribute in the HTML document and is therefore signed as
well, so that it is not possible for an attacker to modify the Content-Type
in the HTTP headers of the signature file to confuse the user agent and
cause it to consider the signature not recognized.
Usage by user agents
When a user agent (i.e web browser) loads a document that contains a signature it should inform the user of its presence. A user must be able to distinguish if a document has a signature compared with a document without a signature.
The user can then request all signatures to be verified, which should indicate who signed the document and if the signature is valid.
To verify the signature(s), the user agent downloads all signatures and runs the verification process for each. The output of the verification should be displayed to the user, indicating the level of trust on the signatures. Signatures with a non-recognized type should be indicated as such.
User agents should detect if a document contains external resources (CSS, JS, images...) and inform the user if that is the case. The user should be able to see the rendered document without including any external resources.
Provisions
The current signature tag can be extended to include other types apart from OpenPGP. The type attribute should be changed to the corresponding MIME type of the format used.
It is expected that other types of signatures also provide a mechanism to determine the authenticity of the signature owner.
See also
- James Tomasino, Signing Posts with gpg (2023)
- Pouya Abbassi, Signing HTML documents using PGP (2021)