A place to cache linked articles (think custom and personal wayback machine)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.html 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. <!doctype html><!-- This is a valid HTML5 document. -->
  2. <!-- Screen readers, SEO, extensions and so on. -->
  3. <html lang="fr">
  4. <!-- Has to be within the first 1024 bytes, hence before the `title` element
  5. See: https://www.w3.org/TR/2012/CR-html5-20121217/document-metadata.html#charset -->
  6. <meta charset="utf-8">
  7. <!-- Why no `X-UA-Compatible` meta: https://stackoverflow.com/a/6771584 -->
  8. <!-- The viewport meta is quite crowded and we are responsible for that.
  9. See: https://codepen.io/tigt/post/meta-viewport-for-2015 -->
  10. <meta name="viewport" content="width=device-width,initial-scale=1">
  11. <!-- Required to make a valid HTML5 document. -->
  12. <title>Plaintext HTTP in a Modern World (archive) — David Larlet</title>
  13. <meta name="description" content="Publication mise en cache pour en conserver une trace.">
  14. <!-- That good ol' feed, subscribe :). -->
  15. <link rel="alternate" type="application/atom+xml" title="Feed" href="/david/log/">
  16. <!-- Generated from https://realfavicongenerator.net/ such a mess. -->
  17. <link rel="apple-touch-icon" sizes="180x180" href="/static/david/icons2/apple-touch-icon.png">
  18. <link rel="icon" type="image/png" sizes="32x32" href="/static/david/icons2/favicon-32x32.png">
  19. <link rel="icon" type="image/png" sizes="16x16" href="/static/david/icons2/favicon-16x16.png">
  20. <link rel="manifest" href="/static/david/icons2/site.webmanifest">
  21. <link rel="mask-icon" href="/static/david/icons2/safari-pinned-tab.svg" color="#07486c">
  22. <link rel="shortcut icon" href="/static/david/icons2/favicon.ico">
  23. <meta name="msapplication-TileColor" content="#f7f7f7">
  24. <meta name="msapplication-config" content="/static/david/icons2/browserconfig.xml">
  25. <meta name="theme-color" content="#f7f7f7" media="(prefers-color-scheme: light)">
  26. <meta name="theme-color" content="#272727" media="(prefers-color-scheme: dark)">
  27. <!-- Documented, feel free to shoot an email. -->
  28. <link rel="stylesheet" href="/static/david/css/style_2021-01-20.css">
  29. <!-- See https://www.zachleat.com/web/comprehensive-webfonts/ for the trade-off. -->
  30. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  31. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  32. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  33. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  34. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  35. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  36. <script>
  37. function toggleTheme(themeName) {
  38. document.documentElement.classList.toggle(
  39. 'forced-dark',
  40. themeName === 'dark'
  41. )
  42. document.documentElement.classList.toggle(
  43. 'forced-light',
  44. themeName === 'light'
  45. )
  46. }
  47. const selectedTheme = localStorage.getItem('theme')
  48. if (selectedTheme !== 'undefined') {
  49. toggleTheme(selectedTheme)
  50. }
  51. </script>
  52. <meta name="robots" content="noindex, nofollow">
  53. <meta content="origin-when-cross-origin" name="referrer">
  54. <!-- Canonical URL for SEO purposes -->
  55. <link rel="canonical" href="https://jcs.org/2021/01/06/plaintext">
  56. <body class="remarkdown h1-underline h2-underline h3-underline em-underscore hr-center ul-star pre-tick" data-instant-intensity="viewport-all">
  57. <article>
  58. <header>
  59. <h1>Plaintext HTTP in a Modern World</h1>
  60. </header>
  61. <nav>
  62. <p class="center">
  63. <a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
  64. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-home"></use>
  65. </svg> Accueil</a> •
  66. <a href="https://jcs.org/2021/01/06/plaintext" title="Lien vers le contenu original">Source originale</a>
  67. </p>
  68. </nav>
  69. <hr>
  70. <p>On the modern web, everything must be encrypted.
  71. Unencrypted websites are treated as relics of the past with browsers declaring
  72. them toxic waste not to be touched (or
  73. <a href="//blog.mozilla.org/security/2020/11/17/firefox-83-introduces-https-only-mode/">even looked at</a>)
  74. and search engines de-prioritizing their content.</p>
  75. <p>While this push for security is good for protecting modern communication, there
  76. is a whole web full of information and services that don’t <em>need</em> to be secured
  77. and those trying to access them from older vintage computers or even through
  78. modern embedded devices are increasingly being left behind.</p>
  79. <p class="alert">Note: This article is mostly directed at those serving personal websites, like
  80. this one, with no expectation of privacy or security by most readers of the
  81. content.
  82. If you are running a commercial website, collecting personal information from
  83. users, or transmitting sensitive data that users would expect to be done
  84. privately, disregard everything here and don’t bother offering your website over
  85. plaintext.</p>
  86. <h2 id="http-upgrading">HTTP Upgrading</h2>
  87. <p>Though it’s less common these days, users may still type in your website URL
  88. manually as opposed to clicking on a link that already includes the <code class="language-plaintext highlighter-rouge">https</code>
  89. scheme.
  90. (Imagine a user hearing your website mentioned on a podcast and they have to
  91. type it into their browser.)</p>
  92. <p>For a URL entered with an <code class="language-plaintext highlighter-rouge">http</code> scheme or, more commonly, no scheme specified,
  93. unless your domain is listed in the
  94. <a href="//www.chromium.org/hsts"><abbr title="Strict Transport Security">STS</abbr> preload list</a>
  95. of the user’s browser or they are using a plugin like
  96. <a href="//www.eff.org/https-everywhere">HTTPS Everywhere</a>, the browser will
  97. default to loading your website over plaintext HTTP.
  98. For this reason, even if your website is only served over HTTPS, it’s still
  99. necessary to configure your server to respond to plaintext HTTP requests with a
  100. 301 or 302 redirect to the HTTPS version of the URL.</p>
  101. <p>If your server is properly configured to send a <code class="language-plaintext highlighter-rouge">Strict-Transport-Security</code>
  102. header, once the user’s browser loads your website’s HTTPS version, the browser
  103. will cache that information for days or months and future attempts to load your
  104. site will default to the HTTPS scheme instead of HTTP even if the user manually
  105. types in an <code class="language-plaintext highlighter-rouge">http://</code> URL.</p>
  106. <h2 id="avoid-forced-upgrading-by-default">Avoid Forced Upgrading by Default</h2>
  107. <p>This forced redirection is a major cause of websites becoming inaccessible on
  108. vintage computers.
  109. Your server responds to the HTTP request with a 301 or 302 status and no
  110. content, and either a) the browser follows the redirection and tries to
  111. negotiate an SSL connection, but your server doesn’t offer legacy SSL versions
  112. or old ciphers so the negotiation fails, or b) the browser just doesn’t support
  113. SSL/TLS at all and fails to follow the redirection.</p>
  114. <p>A real-life example of this is that I recently purchased a Powerbook G4 and
  115. updated it to MacOS X 10.5.8 from 2009.
  116. It has a 1.5Ghz processor and 1.25Gb of RAM, and can connect to my modern WiFi
  117. network and use most of my USB peripherals.
  118. It includes a Mail client that can talk to my IMAP and SMTP servers, and a
  119. Safari web browser which can render fairly modern CSS layouts.
  120. However, it’s unable to view any content at all on Wikipedia simply because it
  121. can’t negotiate TLS 1.2 with the ciphers Wikipedia requires.
  122. Why is a decade-old computer too old to view encyclopedia articles?</p>
  123. <p>A solution to this problem is for websites to continue offering their full
  124. content over plaintext HTTP in addition to HTTPS.
  125. If you’re using Nginx, instead of creating two <code class="language-plaintext highlighter-rouge">server</code> blocks with the <code class="language-plaintext highlighter-rouge">listen
  126. *:80</code> version redirecting to the <code class="language-plaintext highlighter-rouge">listen *:443 ssl</code> version, use a single
  127. <code class="language-plaintext highlighter-rouge">server</code> block with multiple <code class="language-plaintext highlighter-rouge">listen</code> lines, like so:</p>
  128. <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>server {
  129. server_name jcs.org;
  130. listen *:80;
  131. listen *:443 ssl http2;
  132. ssl_certificate ...;
  133. ssl_certificate_key ...;
  134. ...
  135. ssl_protocols TLSv1.2;
  136. }
  137. </code></pre></div></div>
  138. <p>While it may seem counter to the point of this article, I recommend <strong>not</strong>
  139. serving legacy SSL/TLS ciphers like SSLv3 to try to help older browsers.
  140. These old protocols and ciphers are insecure and broken, and I feel it’s better
  141. to make it clear to the user they’re connecting to a website in cleartext than
  142. to offer a false sense of security by having the browser indicate a “secure
  143. connection” when it’s being done over an old, broken protocol.
  144. Also, while it may not be practical anymore, modern browsers might be
  145. <a href="//en.wikipedia.org/wiki/Downgrade_attack">tricked into negotiating</a>
  146. an old, broken cipher if your server still offers it.</p>
  147. <p>Even if you do offer legacy protocols and ciphers to older browsers, your TLS
  148. certificate might be signed by a certificate authority whose root certificate is
  149. not trusted by older browsers.</p>
  150. <h2 id="continue-upgrading-modern-browsers">Continue Upgrading Modern Browsers</h2>
  151. <p>Now that your entire website is being offered to legacy browsers over HTTP,
  152. modern browsers can still be directed to connect over HTTPS for added privacy by
  153. responding to the
  154. <a href="//developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Upgrade-Insecure-Requests"><code class="language-plaintext highlighter-rouge">Upgrade-Insecure-Requests</code></a>
  155. header.
  156. This header is only sent by modern browsers that support
  157. <a href="//developer.mozilla.org/en-US/docs/Web/HTTP/CSP">CSP</a>
  158. when making an HTTP request, so it’s a reasonable indicator that the client is
  159. sufficiently modern and robust that it will be able to negotiate a TLS 1.2
  160. connection if redirected to your site’s HTTPS version.</p>
  161. <p>For Nginx, this can be done inside a <code class="language-plaintext highlighter-rouge">server</code> block by defining a variable
  162. per-request that includes whether it was made over plaintext HTTP and whether it
  163. included an <code class="language-plaintext highlighter-rouge">Upgrade-Insecure-Requests: 1</code> header:</p>
  164. <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>server {
  165. ...
  166. set $need_http_upgrade "$https$http_upgrade_insecure_requests";
  167. location / {
  168. if ($need_http_upgrade = "1") {
  169. add_header Vary Upgrade-Insecure-Requests;
  170. return 301 https://$host$request_uri;
  171. }
  172. ...
  173. }
  174. }
  175. </code></pre></div></div>
  176. <p>This <code class="language-plaintext highlighter-rouge">location</code> block will respond for any request and, for those made over
  177. plaintext HTTP where <code class="language-plaintext highlighter-rouge">$https</code> will be blank and which included an
  178. <code class="language-plaintext highlighter-rouge">Upgrade-Insecure-Requests: 1</code> header, they will be offered a 301 redirection to
  179. the HTTPS version.
  180. The <code class="language-plaintext highlighter-rouge">Vary</code> header is sent so that any caching proxies in the middle won’t cache
  181. the redirect.</p>
  182. <h2 id="content-concessions">Content Concessions</h2>
  183. <p>With legacy browsers now able to access your site, you may want to make some
  184. changes to your HTML and CSS to allow your site to render with some degree of
  185. readability.
  186. I don’t recommend giving it the full IE6 treatment catering to the lowest common
  187. denominator, but at least make the main text of your site readable.</p>
  188. <p>Obviously avoid JavaScript unless it is used progressively, though many older
  189. browsers raise error dialogs at the mere presence of modern JavaScript that
  190. can’t be parsed even if it’s never executed.</p>
  191. <p>Modern CSS and complex layouts can also be a problem even for browsers just a
  192. few years old, so it’s probably best to use them sparingly.
  193. For any <code class="language-plaintext highlighter-rouge">&lt;a&gt;</code> or <code class="language-plaintext highlighter-rouge">&lt;img&gt;</code> tags that are local to your site, use relative links to
  194. avoid specifying a particular scheme.</p>
  195. <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&lt;a href="/posts/blah"&gt;
  196. &lt;img src="/images/..."&gt;
  197. &lt;/a&gt;
  198. </code></pre></div></div>
  199. <p>If you have to specify an absolute URL to another site that is also available
  200. over both HTTP and HTTPS, you can specify it without a scheme or colon and the
  201. browser will use the same <code class="language-plaintext highlighter-rouge">http:</code> or <code class="language-plaintext highlighter-rouge">https:</code> that the document is being viewed
  202. over:</p>
  203. <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&lt;a href="//other.example.com/"&gt;My other site&lt;/a&gt;
  204. </code></pre></div></div>
  205. <h2 id="a-rant-about-gemini">A Rant About Gemini</h2>
  206. <p>Tangentially related,
  207. <a href="//gemini.circumlunar.space/">Gemini</a>
  208. is a modern document transfer protocol that aims to fit between the ancient
  209. <a href="//en.wikipedia.org/wiki/Gopher_(protocol)">Gopher</a>
  210. protocol and the too-modern HTTP web.
  211. Its document markup language is based on
  212. <a href="//en.wikipedia.org/wiki/Markdown">Markdown</a>
  213. so it’s very lightweight and simple to parse without complex HTML/CSS parsers.</p>
  214. <p>It sounds like the perfect thing to bring modern content to vintage computers,
  215. except that its
  216. <a href="//gemini.circumlunar.space/docs/specification.html">protocol</a>
  217. requires all content to be transferred over TLS 1.2 or higher which makes it
  218. nearly impossible to access from a vintage computer or even a modern embedded
  219. system with limited CPU power.</p>
  220. <p>This requirement seems poorly thought out, especially considering the Gemini
  221. protocol doesn’t even support forms (other than a single text box on a search
  222. form) so there’s no chance of users submitting private data, and there’s no
  223. mechanism for client-server sessions so clients can’t be authenticated, meaning
  224. everything served pretty much has to be public anyway.</p>
  225. <p>Its protocol author argues that TLS is just a simple dependency no different
  226. than a TCP server module, so it should be trivial to implement in any client or
  227. server.
  228. But if your computer’s CPU is so slow that a modern TLS negotiation would take
  229. so long as to be unusable, or its
  230. <a href="http://tenfourfox.blogspot.com/2018/02/the-tls-apocalypse-reaches-power-macs.html">platform doesn’t have a TLS 1.2 library</a>
  231. available, that makes it difficult to write a client without depending on an
  232. <a href="//github.com/jcs/sockhole">external system</a>
  233. [<a href="https://oldvcr.blogspot.com/2020/11/fun-with-crypto-ancienne-tls-for.html">2</a>].</p>
  234. <p>In my opinion, the protocol should <em>recommend</em> that servers offer both plaintext
  235. and TLS encrypted versions and <em>recommend</em> that clients prefer TLS, but <em>may</em>
  236. use plaintext if needed.
  237. Clients for modern operating systems can continue enforcing a TLS requirement so
  238. their users aren’t feeling any less secure.</p>
  239. <p>Perhaps just sending actual Markdown text over plaintext HTTP to clients that
  240. ask for it can be the new, old web.</p>
  241. <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Accept: text/markdown,text/plain;q=0.9,*/*;q=0.1
  242. </code></pre></div></div>
  243. <hr />
  244. <p><em>Please don’t contact me to “well ackchyually” me and explain
  245. <a href="/2011/08/17/a_man-in-the-middle_attack_in_the_wild">MITM attacks</a>
  246. and how your terrible ISP inserts ads into your unencrypted web pages and how
  247. you were able to make a Gemini client out of a whistle and some shoelaces.
  248. If you don’t want to make your website content available to stupid old
  249. computers, then don’t.</em></p>
  250. </article>
  251. <hr>
  252. <footer>
  253. <p>
  254. <a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
  255. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-home"></use>
  256. </svg> Accueil</a> •
  257. <a href="/david/log/" title="Accès au flux RSS"><svg class="icon icon-rss2">
  258. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-rss2"></use>
  259. </svg> Suivre</a> •
  260. <a href="http://larlet.com" title="Go to my English profile" data-instant><svg class="icon icon-user-tie">
  261. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-user-tie"></use>
  262. </svg> Pro</a> •
  263. <a href="mailto:david%40larlet.fr" title="Envoyer un courriel"><svg class="icon icon-mail">
  264. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-mail"></use>
  265. </svg> Email</a> •
  266. <abbr class="nowrap" title="Hébergeur : Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33184162340"><svg class="icon icon-hammer2">
  267. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-hammer2"></use>
  268. </svg> Légal</abbr>
  269. </p>
  270. <template id="theme-selector">
  271. <form>
  272. <fieldset>
  273. <legend><svg class="icon icon-brightness-contrast">
  274. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-brightness-contrast"></use>
  275. </svg> Thème</legend>
  276. <label>
  277. <input type="radio" value="auto" name="chosen-color-scheme" checked> Auto
  278. </label>
  279. <label>
  280. <input type="radio" value="dark" name="chosen-color-scheme"> Foncé
  281. </label>
  282. <label>
  283. <input type="radio" value="light" name="chosen-color-scheme"> Clair
  284. </label>
  285. </fieldset>
  286. </form>
  287. </template>
  288. </footer>
  289. <script src="/static/david/js/instantpage-5.1.0.min.js" type="module"></script>
  290. <script>
  291. function loadThemeForm(templateName) {
  292. const themeSelectorTemplate = document.querySelector(templateName)
  293. const form = themeSelectorTemplate.content.firstElementChild
  294. themeSelectorTemplate.replaceWith(form)
  295. form.addEventListener('change', (e) => {
  296. const chosenColorScheme = e.target.value
  297. localStorage.setItem('theme', chosenColorScheme)
  298. toggleTheme(chosenColorScheme)
  299. })
  300. const selectedTheme = localStorage.getItem('theme')
  301. if (selectedTheme && selectedTheme !== 'undefined') {
  302. form.querySelector(`[value="${selectedTheme}"]`).checked = true
  303. }
  304. }
  305. const prefersColorSchemeDark = '(prefers-color-scheme: dark)'
  306. window.addEventListener('load', () => {
  307. let hasDarkRules = false
  308. for (const styleSheet of Array.from(document.styleSheets)) {
  309. let mediaRules = []
  310. for (const cssRule of styleSheet.cssRules) {
  311. if (cssRule.type !== CSSRule.MEDIA_RULE) {
  312. continue
  313. }
  314. // WARNING: Safari does not have/supports `conditionText`.
  315. if (cssRule.conditionText) {
  316. if (cssRule.conditionText !== prefersColorSchemeDark) {
  317. continue
  318. }
  319. } else {
  320. if (cssRule.cssText.startsWith(prefersColorSchemeDark)) {
  321. continue
  322. }
  323. }
  324. mediaRules = mediaRules.concat(Array.from(cssRule.cssRules))
  325. }
  326. // WARNING: do not try to insert a Rule to a styleSheet you are
  327. // currently iterating on, otherwise the browser will be stuck
  328. // in a infinite loop…
  329. for (const mediaRule of mediaRules) {
  330. styleSheet.insertRule(mediaRule.cssText)
  331. hasDarkRules = true
  332. }
  333. }
  334. if (hasDarkRules) {
  335. loadThemeForm('#theme-selector')
  336. }
  337. })
  338. </script>
  339. </body>
  340. </html>