blob: b550e6756be151f9329ee30d4eb35ad7caa27696 [file] [log] [blame] [view]
Christoph Schweringeba114c2023-08-16 18:17:551# Autofill across iframes
2
3Chrome Autofill fills in frame-transcending forms like the following pseudo-code
4example.
5
6```
7<!-- Top-level document URL: https://merchant.example/... -->
8<form>
9 Cardholder name: <input id="name">
10 Credit card number: <iframe src="https://psp.example/..." allow="shared-autofill"><input id="num"></iframe>
11 Expiration date: <input id="exp">
12 CVC: <iframe src="https://psp.example/..." allow="shared-autofill"><input id="cvc"></iframe>
13 <iframe src="https://ads.example/..."><input id="account"></iframe>
14</form>
15```
16
17This applies to address and payment information, but not to passwords.
18
19## The security policy
20
21An autofill fills a form control *candidate* only if one of the following is true:
22
23- the autofill's origin and the *candidate*'s origin are the [same origin];
24- [shared-autofill] is enabled in the *candidate*'s [node document] and one of
25 the following is true:
26 - the autofill's origin and the top-level origin are the [same origin];
27 - the candidate's origin and the top-level origin are the [same origin] and the
28 *candidate*'s autofill value is non-sensitive.
29
30The terminology used above is defined in the [appendix](#appendix-terminology).
31
32This policy is the [eligibility for autofill] definition plus the additional
33"... and one of the following is true" conjunct in the [shared-autofill] clause.
34
35The policy is implemented in [FormForest::GetRendererFormsOfBrowserForm()].
36
37## The rationale
38
39The example form above exhibits a common pattern: at the time of writing, about
4020% of the payment forms on the web span multiple origins. Most commonly, the
41cardholder name field's origin is the top-level origin, whereas the credit card
42number is in a cross-origin iframe hosted by the payment service provider (PSP).
43
44These iframes are typically styled so that they seamlessly integrate with the
45merchant's page -- the user is not made aware that multiple frames and origins
46are involved. Yet the different origins isolate the payment information from the
47merchant's website, which helps them comply with the payment card industry's
48data security standard (see Section 2.2.3 of the [PCI-DSS best practices]).
49
50Chrome Autofill's objective is to fill fields that the user expects to be
51filled, even if those fields cross origins, while protecting the user against
52possibly malicious sub-frames. Intuitively, we support two "directions":
53
54- "Downwards": An autofill may fill fields in descendant documents where
55 [shared-autofill] is enabled. In our example, an autofill initiated on the
56 cardholder name field may fill the credit card number field.
57- "Upwards": An autofill may fill certain values in ancestor documents. In our
58 example, an autofill initiated on the credit card number field may fill the
59 cardholder name field.
60
61We restrict the values that may be filled "upwards" especially to prevent
62leaking sensitive payment information -- credit card numbers and CVCs that the
63PCI-DSS intends to protect -- into the merchant's page. The "non-sensitive"
64values that we allow to be filled "upwards" are credit card types, cardholder
65names, and expiration dates.
66
67The terms "upwards" and "downwards" are imprecise: our security policy doesn't
68refer to the [top-level traversable]'s [node document], but rather to its
69[origin], the top-level origin. This way, Autofill works the same when, for example,
70the cardholder name is hosted in a same-origin iframe: `<iframe
71src="https://merchant.example/..."><input id="name"></iframe>`.
72
73Our security policy does not allow "upwards" or "downwards" filling to and from
74arbitrary documents. It only allows filling "upwards to" main-origin documents
75and "downwards from" main-origin documents. This simplifies reasoning about the
76security policy as well as the implementation, and is still sufficient for
77real-world payment forms.
78
79The following table illustrates which fields may be filled in our example form
80depending on the autofill's origin:
81
82| Autofill's origin | `name` | `num` | `exp` | `cvc` | `account` |
83|----------------------------|:--------:|:--------:|:--------:|:--------:|:---------:|
84| `https://merchant.example` | &#10004; | &#10004; | &#10004; | &#10004; | &#10006; |
85| `https://psp.example` | &#10004; | &#10004; | &#10004; | &#10004; | &#10006; |
86| `https://ads.example` | &#10004; | &#10006; | &#10004; | &#10006; | &#10004; |
87
88## Appendix: Terminology
89
90An *autofill* is an operation that fills one or many form control elements in
91the [fully active descendants of a top-level traversable with user attention].
92An autofill can only be initiated on a [focused] form control element.
93
94An autofill *fills a form control* if it changes the form control's [value]. The
95value after the autofill is the *form control's autofill value*.
96
97A form control's autofill value is *non-sensitive* if it is a credit card type,
98a cardholder name, or a credit card expiration date.
99
100A *form control's origin* is its [node document]'s [origin].
101An *autofill's origin* is the [focused] form control's origin.
102The *top-level origin* is the [top-level traversable]'s [active document]'s [origin].
103
104*[shared-autofill] is enabled in a document* if the [Is feature enabled in
105document for origin?] algorithm on [shared-autofill], the document, and the
106document's [origin] returns `Enabled`.
107
108*TODO*: Update link to [eligibility for autofill] once the
109[PR](https://github.com/whatwg/html/pull/8801) is closed.
110
111[FormForest::GetRendererFormsOfBrowserForm()]: https://source.chromium.org/chromium/chromium/src/+/main:components/autofill/content/browser/form_forest.cc;l=618-623;drc=94fbbc584c5d42f0097a9cb28b355853d2b34658
112[active document]: https://html.spec.whatwg.org/#nav-document
113[eligibility for autofill]: https://schwering.github.io/html/#eligible-for-autofill
114[Is feature enabled in document for origin?]: https://w3c.github.io/webappsec-permissions-policy/#algo-is-feature-enabled
115[focused]: https://html.spec.whatwg.org/#focused
116[fully active descendants of a top-level traversable with user attention]: https://html.spec.whatwg.org/#fully-active-descendant-of-a-top-level-traversable-with-user-attention
117[same origin]: https://html.spec.whatwg.org/multipage/browsers.html#same-origin
118[node document]: https://dom.spec.whatwg.org/#concept-node-document
119[origin]: https://dom.spec.whatwg.org/#concept-document-origin
120[PCI-DSS best practices]: https://www.pcisecuritystandards.org/
121[shared-autofill]: https://schwering.github.io/shared-autofill/
122[top-level traversable]: https://html.spec.whatwg.org/#top-level-traversable
123[value]: https://html.spec.whatwg.org/#concept-fe-value