Skip to content

Instantly share code, notes, and snippets.

@mems
Last active November 3, 2023 11:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mems/cc6ea1240d6d4a7d179bd5581f084560 to your computer and use it in GitHub Desktop.
Save mems/cc6ea1240d6d4a7d179bd5581f084560 to your computer and use it in GitHub Desktop.
SLA for website third parties

Third party SLA

About

Inspiration:

Definitions

The key words MUST, MUST NOT, SHOULD, SHOULD NOT, MAY are to be interpreted as described in RFC 2119. For readability, these words do not appear in all uppercase letters.

User privacy

Accessibility

TODO: TBD

User experience

  • must use client design system
  • must allow + char in email address1
  • must play media only on user interaction2

Security

  • should not use deprecated HTTP-Based Public Key Pinning
  • must use HTTPS for all resources, with at least a rate B by Qualys SSL Labs for all domains and subdomains used (CN and SAN). Must not use distrusted certificates3

Network

  • must support gzip and br encoding for text resources (JavaScript, HTML, CSS, JSON)4
  • must support HTTP/2.0 and should support HTTP/3.0, if more than one resource is used
  • must serve all resources with the Timing-Allow-Origin: * header5
  • must serve all JavaScript resources that don't contains personal data with the Access-Control-Allow-Origin: * header, and loaded it with crossorigin="anonymous" attribute (or dynamicaly with the property script.crossOrigin="anonymous")6
  • must use correct (and official) media type (Content-Type header)
  • should support fixed versions for scripts and stylesheets to allow subresource integrity7
  • must minify resources with tools likes Terser, SWC, esbuild, lightningcss, csso, cssnano, mozjpeg, etc.8
  • must use appropriate formats for the web: AVIF, WebP, JPEG, MP4, etc.

Client side API / widget

For reasons of performance, console pollution/spam, global namespace pollution, name collision, clarity, bad practice, the API or widget:

  • may support to used via an iframe (isolated document context)9

  • must not use blocking scripts (no document.write()), all scripts must support async or defer loading

  • must not use synchronous XMLHttpRequest

  • must not use any other Console API than console.warn() and console.error(), unless a debug mode is enabled

  • TODO: TBD reflow, setInterval, post message must not take more than 100ms to execute

  • must use non-passive event listeners only when it's a necessity10

  • must send tacking data with fetch keep alive or beacon API (no pixel or "empty" tracking images)11

  • must not add method or properties to hosts and native objects, if not in an isolated document context

  • must use pure polyfills, if not in an isolated document context

  • may expose a global object, must not expose anything else, if not in an isolated document context:

    may:

     window.vendorName = {
     	prop1: 123,
     	prop2: 456,
     	get prop3(){},
     	set prop3(){},
     	method1(){},
     	method2(){},
     };

    must not:

     const value1 = 123;
     function method1(){};
     window.method2 = () => {};
  • must provide a reliable way to programmatically know when the client side API (for read or write) is available:

     (window.vendorName = window.vendorName || []).push(
     	(vendorAPI) => {/*read/write vendor's API*/},
     	(vendorAPI) => {/*read/write vendor's API*/},
     );

    In case of iframe (isolated document context), the content of the frame should response to a post message to request the state: window.postMessage("vendornameapiready", targetOrigin, transfer)12. In case of pure CSS code, define a global variable.

  • must provide a reliable way, when write data is needed, use at least one of the following methods (in preference order):

    1. script querystring: <script src="https://3rdpty.com/script?tenant=1234&amp;version=5678" defer></script> or <script src="https://3rdpty.com/1234/5678/script" defer></script>

    2. attributes of the script: <script src="https://3rdpty.com/script" defer data-tenant="1234" data-version="5678"></script>

    3. to register statements:

      (window.vendorName = window.vendorName || []).push(
      	["method1", arg1, arg2],
      	["method2", arg3, arg4],
      );
  • must provide a reliable way to programmatically interact with vendor's events13:

     window.addEventListener("vendornamesomething", ({detail}) => {/*do something with the detail*/});
     // Or
     (window.vendorName = window.vendorName || []).push(
     	(vendorAPI) => vendorAPI.addEventListener("something", (event) => {/*do something with the event*/}),
     );

    The name of events must respect the naming convention of the HTML standard (lowercase, concatenated, alpha only, present form, etc.)14.

  • must name global tokens (events name, global JS variables, DOM elements ID, cookie name / storage keys, CSS variables, etc.) with at least 4 chars length and prefixed with the vendor name (that start with an alpha char)15

  • must not use CSS !important specificity

  • must not use unload event. Use pagehide instead16

  • must not keep references to window.opener when it's not necessary17

  • must not keep open connections (IndexedDB, WebSocket and WebRTC) when the page is hidden18

Footnotes

  1. Picto thématique Règle n° 23 - Le site accepte les alias mail contenant le signe + - Checklist Opquast

  2. Règle n° 119 - Les vidéos sont déclenchées par l'utilisateur - Checklist Opquast and Règle n° 120 - Les sons sont déclenchés par l'utilisateur - Checklist Opquast

  3. Règle n° 192 - Toutes les pages utilisent le protocole HTTPS - Checklist Opquast, Règle n° 193 - Les certificats de sécurité sont signés et en cours de validité - Checklist Opquast and Google Online Security Blog: Distrust of the Symantec PKI: Immediate action needed by site operators

  4. Règle n° 219 - Le serveur transmet des contenus compressés aux clients qui les acceptent - Checklist Opquast

  5. Timing-Allow-Origin - HTTP | MDN

  6. Muted errors - HTML Standard (errors for cross-origin scripts are muted)

  7. Subresource Integrity and Major sites running unauthenticated JavaScript on their payment pages – Terence Eden's Blog

  8. Règle n° 223 - Les scripts du site sont minifiés - Checklist Opquast, Règle n° 222 - Les feuilles de style du site sont minifiées - Checklist Opquast, Minify and compress network payloads and Minify CSS.

  9. The purpose is to make a separation layer between first party and third party and it dependencies for risk mitigation of:

    • availability issue
    • invalid/incorrect HTML syntax
    • cookies name conflict
    • javascript global variables conflicts
    • incompatible host object extension
    • javascript library version conflict
    • style conflict/override
    • script errors
    • security issue (data leaking, malware, etc.)
    • web performance (blocking rendering, blocking main Javascript thread)

    Use postMessage API for exchanges between the iframe and the host document

  10. Using passive listeners

  11. fetch() global function - Web APIs | MDN and Navigator.sendBeacon() - Web API | MDN

  12. Window.postMessage() - Web API | MDN

  13. Creating and triggering event - Developer guide | MDN and EventTarget: EventTarget() constructor - Web APIs | MDN

  14. Use casing rules consistent with existing APIs - Web Platform Design Principles

  15. About write good names:

  16. Never use the unload event - Back/forward cache

  17. Avoid window.opener references - Back/forward cache

  18. Always close open connections before the user navigates away - Back/forward cache

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment