|
| 1 | +<!doctype html> |
| 2 | +<html> |
| 3 | +<head> |
| 4 | + <title>Dillo RFC-006: Signatures in HTML</title> |
| 5 | + <!-- The RFC is also signed :-) --> |
| 6 | + <link rel="signature" type="application/pgp-signature" href="index.html.sig"> |
| 7 | + <style> |
| 8 | + body { |
| 9 | + background: white; |
| 10 | + line-height: 1.5; |
| 11 | + margin: 3em; |
| 12 | + font-size: 16px; |
| 13 | + font-family: sans-serif; |
| 14 | + max-width: 72ch; |
| 15 | + } |
| 16 | + h1 { font-size: 24px; margin-bottom: 1em; } |
| 17 | + header { border: solid 1px #ddd; background: #f5f5f5; padding: 0.25em 1em } |
| 18 | + dt { font-weight: bold } |
| 19 | + dd { margin-left: 2ch; } |
| 20 | + ol { margin-left: 2ch; } |
| 21 | + pre { margin: 0.5em; } |
| 22 | + </style> |
| 23 | +</head> |
| 24 | +<body> |
| 25 | + <h1>Dillo RFC-006: Signatures in HTML</h1> |
| 26 | + <header> |
| 27 | + <dl> |
| 28 | + <dt>State</dt><dd>Draft</dd> |
| 29 | + <dt>Updated</dt><dd>2025-11-15</dd> |
| 30 | + <dt>Author</dt><dd>Rodrigo Arias Mallo |
| 31 | + (<a href="mailto:rodarima@gmail.com">rodarima@gmail.com</a>) |
| 32 | + </dd> |
| 33 | + </dl> |
| 34 | + </header> |
| 35 | + <main> |
| 36 | + <h2>Abstract</h2> |
| 37 | + |
| 38 | + <p>This document introduces a new link tag to specify a signature in HTML |
| 39 | + documents based on OpenPGP. It also describes how to present the signature |
| 40 | + information to users reading the document and how to verify it.</p> |
| 41 | + |
| 42 | + <h2>Motivation</h2> |
| 43 | + |
| 44 | + <p>When a user fetches an HTML document via the HTTPS protocol from a given |
| 45 | + site, the user can trust that the site is legitimate by checking the TLS |
| 46 | + certificate and follow the chain until a trusted CA. However, losing the DNS |
| 47 | + record of the site would cause all content to lose the trust that it had |
| 48 | + originally, even if the content is copied verbatim elsewhere. |
| 49 | + |
| 50 | + <p>A mirrored copy cannot be trusted unless the author controls the |
| 51 | + mirror server as well. |
| 52 | + |
| 53 | + <p>Signing the HTML document itself would allow users to verify that the |
| 54 | + content is legitimate and has not been tampered with, regardless of the |
| 55 | + transport mechanism used to deliver it to the user. |
| 56 | + |
| 57 | + <p>The <a href="https://www.rfc-editor.org/rfc/rfc9580">OpenPGP specification |
| 58 | + RFC-9580</a> describes an standard on how to sign and verify |
| 59 | + signatures and several implementations are widely available to users, so it |
| 60 | + will be used as the signature format. |
| 61 | + |
| 62 | + <h2>Introduction</h2> |
| 63 | + |
| 64 | + <p>An OpenPGP signature is added to an HTML document by first including a |
| 65 | + <code>link</code> tag in the <code>head</code> section with the following |
| 66 | + three mandatory attributes: |
| 67 | + <ul> |
| 68 | + <li>The <code>rel</code> attribute must be set to |
| 69 | + <code>signature</code>.</li> |
| 70 | + <li>The <code>type</code> attribute must be set to the MIME type of the |
| 71 | + OpenPGP signature file which is |
| 72 | + <code>application/pgp-signature</code>.</li> |
| 73 | + <li>The <code>href</code> attribute must be set to the location of the |
| 74 | + signature file.</li> |
| 75 | + </ul> |
| 76 | + |
| 77 | + <p>Multiple signatures can be added by including multiple <code>link</code> |
| 78 | + tags in the head. All signature tags must be added to the HTML document |
| 79 | + before the signatures are created. The signature files are then computed |
| 80 | + from the HTML document and placed in their respective files as described by |
| 81 | + the <code>href</code> attribute. |
| 82 | + |
| 83 | + <h3>Example with GnuPG</h3> |
| 84 | + <p>To add an OpenPGP signature to an <code>index.html</code> HTML |
| 85 | + document using GnuPG: |
| 86 | + <ol> |
| 87 | + <li>Include a <code>link</code> tag in the head with the attribute |
| 88 | + <code>rel="signature"</code> as follows: |
| 89 | + <pre><link rel="signature" |
| 90 | + type="application/pgp-signature" |
| 91 | + href="index.html.sig"></pre> |
| 92 | + </li> |
| 93 | + <li>Sign the HTML document and generate a detached signature with the |
| 94 | + specified name. Example with GnuPG: |
| 95 | + <pre>$ gpg --output index.html.sig --detach-sig index.html</pre> |
| 96 | + </li> |
| 97 | + <li>Download both the HTML and signature files then verify that the |
| 98 | + signature matches. Example with GnuPG: |
| 99 | + <pre>$ gpg --verify index.html.sig index.html</pre> |
| 100 | + </li> |
| 101 | + </ol> |
| 102 | + <p>This HTML document is also signed following the above steps.</p> |
| 103 | + |
| 104 | + <h2>Limitations</h2> |
| 105 | + |
| 106 | + <p>The signature <strong>only covers the HTML file</strong>, not any |
| 107 | + external resource that may be referenced such as CSS, JS, images, fonts or |
| 108 | + documents in iframes. Those resources could be altered in such a way that |
| 109 | + the content of the document may change. |
| 110 | + |
| 111 | + <p>A simple example can be build with a <code>style.css</code> like so: |
| 112 | + <pre>.hide { display: none; }</pre> |
| 113 | + |
| 114 | + <p>And a segment of <code>index.html</code> that hides content when the CSS |
| 115 | + file is loaded, changing the meaning of the sentence: |
| 116 | + <pre>I <span class=hide>don't</span> accept the contract.</pre> |
| 117 | + |
| 118 | + <p>Similarly, CSS media rules or JavaScript code may cause elements to |
| 119 | + change causing the meaning to change depending on the user reading the |
| 120 | + document or other factors. |
| 121 | + |
| 122 | + <p>Authors should not include any additional resources in a signed HTML |
| 123 | + file. They won't be loaded when a user requests to see the HTML signed |
| 124 | + document only. |
| 125 | + |
| 126 | + <h2>Considerations</h2> |
| 127 | + |
| 128 | + <p>The current model assumes that authors won't create misleading |
| 129 | + documents, as it would be possible to change the meaning of the document |
| 130 | + even without including external resources, using embedded JS or CSS rules. |
| 131 | + |
| 132 | + <p>It is not enough to verify that a signature is valid, the key must be |
| 133 | + trusted by the user reading the document. Otherwise an actor could simply |
| 134 | + sign a changed document with its own key and pretend it is the original |
| 135 | + author. Users are expected to know how the web of trust works. |
| 136 | + |
| 137 | + <p>An attacker that is able to control the content of the HTML document |
| 138 | + (for example transmitted over HTTP) could simply remove any signatures and |
| 139 | + tamper the document. We assume that trust cannot be established unless a |
| 140 | + valid signature is present. |
| 141 | + |
| 142 | + <p>The type of the signature is exclusively determined by the |
| 143 | + <code>type</code> attribute in the HTML document and is therefore signed as |
| 144 | + well, so that it is not possible for an attacker to modify the Content-Type |
| 145 | + in the HTTP headers of the signature file to confuse the user agent and |
| 146 | + cause it to consider the signature not recognized. |
| 147 | + |
| 148 | + <h2>Usage by user agents</h2> |
| 149 | + |
| 150 | + <p>When a user agent (i.e web browser) loads a document that contains a |
| 151 | + signature it should inform the user of its presence. A user must be able to |
| 152 | + distinguish if a document has a signature compared with a document without a |
| 153 | + signature. |
| 154 | + |
| 155 | + <p>The user can then request all signatures to be verified, which should |
| 156 | + indicate who signed the document and if the signature is valid. |
| 157 | + |
| 158 | + <p>To verify the signature(s), the user agent downloads all signatures and |
| 159 | + runs the verification process for each. The output of the verification |
| 160 | + should be displayed to the user, indicating the level of trust on the |
| 161 | + signatures. Signatures with a non-recognized type should be indicated as |
| 162 | + such. |
| 163 | + |
| 164 | + <p>User agents should detect if a document contains external resources (CSS, |
| 165 | + JS, images...) and inform the user if that is the case. The user should be |
| 166 | + able to see the rendered document without including any external resources. |
| 167 | + |
| 168 | + <h2>Provisions</h2> |
| 169 | + |
| 170 | + <p>The current signature tag can be extended to include other types apart |
| 171 | + from OpenPGP. The type attribute should be changed to the corresponding MIME |
| 172 | + type of the format used. |
| 173 | + |
| 174 | + <p>It is expected that other types of signatures also provide a mechanism to |
| 175 | + determine the authenticity of the signature owner. |
| 176 | + |
| 177 | + <h2>See also</h2> |
| 178 | + <ul> |
| 179 | + <li>James Tomasino, |
| 180 | + <i><a href="https://labs.tomasino.org/signing-posts-with-gpg/"> |
| 181 | + Signing Posts with gpg</a></i> (2023)</li> |
| 182 | + <li>Pouya Abbassi, |
| 183 | + <i><a href="https://pouyacode.net/signing-webpages.html"> |
| 184 | + Signing HTML documents using PGP</a></i> (2021)</li> |
| 185 | + </ul> |
| 186 | + </main> |
| 187 | +</body> |
| 188 | +</html> |
0 commit comments