User Tools

Site Tools


programming:registration

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
programming:registration [2025/02/18 15:27] – formatting fix karelkubicekprogramming:registration [2026/10/08 20:49] (current) – Finish PII leakage collateral: back-links and provenance; Authored by Claude karel.kubicek.claude
Line 1: Line 1:
 ====== Automating Login and Registration to Websites ====== ====== Automating Login and Registration to Websites ======
  
-WiP: brainstorming below.+Logged-out is the default crawl in this literature. Of the 857 web crawls in this corpus, **553 (64.5%)** are labelled ''none'' (did not authenticate), **204 (23.8%)** do not say, and the schema marks **81 (9.5%)** as some kind of login or registration. That 81 is a mixed bag: lab scanners of applications the authors control, one social-network account, marketplace cookies, and eleven papers the schema simply mislabelled. The figure this page publishes is the **17 papers (2.0% of 857)** that, among those 81, created accounts or logged in as an instrument on the sites they were measuring — a hand split of the schema hits, not a full-text census of the 776 papers the schema did not mark as logged in.
  
-===== Automated Login =====+<WRAP important> 
 +Do not read the 81, or the 42 + 24 + 15 split next to it, as "papers that logged in." ''crawlConfig.authentication'' has **one evidence quote for the whole object**, so the label cannot be checked from the quote. A neighbouring page published 81/857 = 9.5% without a role split; this page keeps that schema count visible and replaces it, for advice, with the 17. The 17 is a hand split of those 81 (plus a closed SCHEMA_MISS list that is not unioned in). It is not a census of all 857. SSO as a schema value is **0** among web crawls — the one corpus ''sso'' label is an Android subscription-app study. Papers that //measured// SSO still exist; they are labelled ''none'' or something else. 
 +</WRAP>
  
-Shepherd by Jonker et al. (2020)+Getting past a login is a different job from clicking a subpage. Depth, typing-versus-''fill()'', and the half of the web you do not measure live on [[Programming:Interaction]]. Consent banners are [[Privacy:Consent]]. Whether the profile survives between visits is [[Programming:Stateful Stateless]]. This page is the remaining four jobs: **log in with credentials you already have**, **create accounts at scale**, **subscribe to a newsletter**, and **fill a form without submitting it**.
  
-===== SSO =====+===== What to read first =====
  
-How to use it for large scale web measurements, references to:+^ Paper ^ Why ^ 
 +| Drakonakis et al., CCS 2020, //Cookie Hunter// {[drakonakis2020_cookie]} | The scale-registration baseline: **13.7%** registered and logged in of 168,594 signup domains; **25,242** accounts created (not the same figure). They **refused** a human CAPTCHA farm | 
 +| Rautenstrauch et al., IEEE S&P 2024, //To Auth or Not To Auth// {[rautenstrauch2024_auth]} | Why you bother: 200 sites where automated login then kept working; more than 400 accounts made by hand; the failure modes that ate the rest of the list | 
 +| Kaizer et al., IMC 2016 {[kaizer2016_characterizing]} | The existence proof that logged-in and logged-out are different websites: 345 sites, 14 Alexa categories, accounts created by hand, Selenium for the login | 
 +| Kubicek et al., TheWebConf 2024 {[kubicek2024_register]} | The largest registration crawl in the bibliographic index. **In the index, absent from the extraction** — cited from the author PDF, not from ''paper.cols.txt'' | 
 +| Jonker et al., MADWeb 2020 {[jonker2020_shepherd]} | How to //verify// a login. Out of this corpus (NDSS workshop). 7,113 verified logins with BugMeNot credentials | 
 +| Englehardt et al., PoPETs 2018 {[englehardt2018_email]} | Newsletter signup is a lighter instrument than full registration: 3,335 form attempts, 12,618 emails from 902 senders |
  
-  * Dimova et al. (2023) +===== Four jobs =====
-  * Ghasamisharif et al. (2018) +
-  * Zhou et al. (2014) - might be too old +
-  * any other?+
  
-===== Automated Registration and Newsletter Subscription =====+  - **Login with existing credentials.** Shepherd {[jonker2020_shepherd]} is the method paper. Calzavara et al. {[calzavara2014_cookiejar]} is the cookie-identification paper (70 sites). Kaizer et al. {[kaizer2016_characterizing]} and Rautenstrauch et al. {[rautenstrauch2024_auth]} are the measurement papers that then crawl while logged in. 
 +  - **Create accounts at scale.** Cookie Hunter {[drakonakis2020_cookie]}, the login-policies crawl {[alroomi2023_login]}, the password-policies crawl {[alroomi2023_password]}, Tripwire's honey accounts {[deblasio2017_tripwire]}, and Kubicek et al. {[kubicek2024_register]}. 
 +  - **Newsletter / mailing-list signup.** Lighter than a passworded account. Englehardt et al. {[englehardt2018_email]} automated it; Kubíček et al. {[kubicek2022_emails]} registered by hand on 666 of 1,000 sites. Mathur et al. {[mathur2023_political]} is the political-email follow-up, **outside this corpus**. 
 +  - **Fill without submitting.** Senol et al. {[senol2022_leaky]} filled email on 52,055 of 99,380 loaded Tranco 100k sites and left. Chatzimpyrros et al. {[chatzimpyrros2020_register]} did the registration-form version on 200,000 sites, **outside this corpus**. Typing versus setting ''value'' is on [[Programming:Interaction]] — do not duplicate it here.
  
-  * Drakonakis et al. (2020) +===== What the field actually did =====
-  * Kubicek et al. (2024) +
-  * Englehardt et al. (2018) and Mathur et al. (2020) follow-up+
  
 +Population: **857 web crawls** (''crawled'' and ''platforms'' includes ''web''). The 1,120-crawled row that includes mobile and network scans is the OVERVIEW.md number (authentication stated by 779/1,120 = 69.6%); it is not this page's denominator.
  
-===== Other =====+^ ''authentication'' ^ Papers ^ Share of 857 ^ 
 +| ''none'' | 553 | 64.5% | 
 +| ''not-stated'' | 204 | 23.8% | 
 +| ''account-registration'' | 42 | 4.9% | 
 +| ''manual-login'' | 24 | 2.8% | 
 +| (no ''crawlConfig'' object) | 19 | 2.2% | 
 +| ''automated-login'' | 15 | 1.8% | 
 +| ''sso'' | 0 | — |
  
 +**The 553 ''none'' row is mostly an inference, and some of it is wrong.** A hand audit of the ''none'' labels on a **different and smaller population** — the **145** of the **260 platform-subject papers with a crawl configuration** ([[design:platforms]]), not these 857 web crawls — read each paper's own text rather than the shared ''crawlConfig'' quote and found **119 (82.1%)** where the paper says nothing about its authentication posture either way, **12 (8.3%)** where it states the collection was unauthenticated, **8 (5.5%)** ambiguous, and **6 (4.1%)** **contradicted by the paper's own text** — one of them scored ''none'' while its own ''crawlConfig'' evidence quote reads "we scrape user photographs from Instagram using an alias account". The two populations overlap but are not the same set, so 82.1% and 4.1% do not transfer to the 553; the transferable conclusion is that ''none'' on this field is the extractor's reading of silence far more often than it is a reading of the paper, so **the 553 is an upper bound and the 81 is a lower one**. Per-paper verdicts: [[provenance:design:platforms]].
  
-  * Automated interaction wit hforms but without submission: Senol et al. (2022) and Chatzimpyrros et al. (2019)+The 42 + 24 + 15 = 81. Hand-read, they split like this. A paper can do more than one of these; the label is the job that decided whether it belongs on this page.
  
 +^ Role ^ Papers ^ Share of 81 ^ What it is ^
 +| scale-register | 8 | 9.9% | automated account creation on the sites being measured |
 +| scale-login | 9 | 11.1% | automated login with credentials that already exist |
 +| **instrument (union of the two)** | **17** | **21.0% of 81; 2.0% of 857** | the published figure |
 +| manual-session | 9 | 11.1% | a human created the account or logged in; the crawler reused it |
 +| lab-scanner | 14 | 17.3% | authenticated scan of a web application they control |
 +| sso-study | 2 | 2.5% | SSO is the phenomenon, not a way into a ranked list |
 +| newsletter | 1 | 1.2% | mailing-list / marketing-email registration inside the 81 |
 +| marketplace | 6 | 7.4% | underground / forum / darkweb session |
 +| social | 10 | 12.3% | accounts on one platform (YouTube, Facebook, Xing, …) |
 +| other | 11 | 13.6% | real accounts, not a ranked-list login crawl |
 +| mislabel | 11 | 13.6% | did not authenticate to the sites they measured |
  
-/* +Four papers the schema labelled ''none'' are load-bearing on this page anyway, and are **not** unioned into the 81: Englehardt et al. {[englehardt2018_email]} (newsletter bot), Ghasemisharif et al. {[ghasemisharif2018_sso]} (SSO census), Senol et al. {[senol2022_leaky]} (fill without submit), Dimova et al. {[dimova2023_ssomething]} (OAuth buttons, no RP login at scale).
-This is a comment not visible on the page. It outlines the syntax (for more, go to https://measuretheweb.org/wiki/syntax), especially that related to bibliography. Remove it once you created the page. If you use any citations (documented at bottom), keep the References section.+
  
-===== Header Level 2 ===== +Kubicek et al. {[kubicek2024_register]} is in ''corpus2/.meta'' (DOI 10.1145/3589334.3645709) and **not** in ''extractions.jsonl''. There is no ''paper.cols.txt''. Every figure from it below is from the author PDF at ''people.inf.ethz.ch/basin/pubs/www24.pdf'', read 2026-08-27.
-==== Header Level 3 ====+
  
-=== Links ===+The 17 instrument papers, in year order: SSOScan {[zhou2014_ssoscan]}; Calzavara et al. {[calzavara2014_cookiejar]}; Tripwire {[deblasio2017_tripwire]}; Cookie Hunter {[drakonakis2020_cookie]}; SAAT {[ghasemisharif2022_saat]}; password policies {[alroomi2023_password]}; login policies {[alroomi2023_login]}; To Auth {[rautenstrauch2024_auth]}; plus nine scale-login crawls (IMC 2016 {[kaizer2016_characterizing]} among them). The list is in the report script.
  
-External links are recognized automatically: www.google.com, but if you want a link text: [[http://www.google.com|This Link points to google]].+Year shape of the 17, of web crawls in that bucket. 2025–2026 is provisional:
  
-Internal links are created by using square brackets. You can either just give a [[pagename]] or use an additional [[pagename|link text]].+^ Bucket ^ Web crawls ^ Schema-logged ^ Instrument ^ 
 +| 2010–2013 | 80 | 7 | 0 | 
 +| 2014–2017 | 130 | 18 | 6 | 
 +| 2018–2021 | 241 | 14 | 2 | 
 +| 2022–2024 | 253 | 25 | 7 | 
 +| 2025–2026* | 153 | 17 | 2 |
  
-=== Lists ===+===== Automated login =====
  
-Lists and their levels are decided by indentation (2 spaces = 1 level)+The method that is still the one to copy is Shepherd {[jonker2020_shepherd]}. **Out of this corpus** (MADWeb 2020, an NDSS workshop). Four steps: find a login start, submit, check the response, **verify**. The last step is the one people skip. Shepherd runs a check twice — once with the candidate session's cookies, once without — and claims a login only when the check succeeds with cookies and fails without them. Three checks: a logout button or user identifier after submit; the same on the landing page; an attempt to re-open the login area (which a well-designed site should refuse). Verification accuracy on a 100-site sample was ≥97%.
  
-  - this is 1. item +On BugMeNot credentials for 49,846 sites, 23,088 were rejected as invalid, 26,758 remained, and Shepherd verified **7,113** logins (26.6% of the remainder; a lower bound). Facebook SSO, separately, verified **383**. Finding the login area on a 5,000-site Alexa sample: landing page 225, URLs with login terms 1,119, clickables 1,149, standard URLs 1,366, search engines 1,948, **combined 2,759**. The methods are disjoint enough that combining them is the result; landing pages almost never contain the form, but they have to run first because everything else needs the post-redirect domain. BugMeNot is crowd-sourced credentials with site-owner removal and a ban on banks and age-restricted sites; that is an ethics fact about //this// instrument, not a recommendation to use it.
-  - 2. item +
- - nested a. item +
-  * bullet-point item+
  
-=== Code ===+Calzavara et al. {[calzavara2014_cookiejar]} is the other half of the login problem: once you are in, **which cookies are the session**. They built a gold set from 70 Alexa sites; a naïve script was wrong on 2 of 70. That is identification, not login.
  
-For a short inline monospace, use ''double quote''. For proper code (but in a separate paragraph), use ''<code LANG>'':+Kaizer et al. {[kaizer2016_characterizing]} created accounts **manually** on 345 sites in 14 Alexa categories, then used Selenium to log in. Logged-in users saw more ads and more privacy-concerning behaviour. If your question is "what does the logged-in web look like", this is still the paper that posed it cleanly.
  
-<code python> +Rautenstrauch et al. {[rautenstrauch2024_auth]} is the 2024 version of that question for security headers and XSS. Semi-automatic account framework; **more than 400 accounts by hand**; then **200 sites** where automated login kept succeeding. Playwright 1.33, Gmail for email verification. The rest of the list died of captcha loops / timeouts / blocks (**177**), payment or phone (**170**), or SSO-only (**88**). Those three numbers are why "we logged in where we could" is a biased sample: the survivors are the sites that let a research crawler in.
-string = "World" +
-print(f'Hello {string}') +
-</code>+
  
-For large code, use ''<file LANG filename>'', it will make code downloadable. For instance:+The script below is Shepherd's last step on two HTML fixtures. It does not find the form and it does not talk to the network. It does refuse a substring match of "session" against "sessionStorage", and it does refuse English prose that says "log out".
  
-<file php example.php> +<file python login_diff.py> 
-<?php echo "hello world!"; ?>+#!/usr/bin/env python3 
 +"""Differential login-success check (Shepherd's last step). 
 + 
 +A 200 and a page that still has a login form is not a login. Jonker, Karsch, 
 +Krumnow and Sleegers (MADWeb 2020) verify a candidate login by running the 
 +same check twice: once with the cookies from the candidate session, once 
 +without. A login is claimed only when the check succeeds with cookies and 
 +fails without them. 
 + 
 +This script is that comparison on two HTML snapshots. It does not find the 
 +login form, submit credentials, or talk to the network. Those are earlier 
 +Shepherd steps; this is the one that is easy to get wrong by substring. 
 + 
 +    python3 login_diff.py                  # self-tests, then the documented run 
 +    python3 login_diff.py --logged-out out.html --logged-in in.html 
 + 
 +Exit 0 if the logged-in snapshot has at least one login marker that the 
 +logged-out snapshot does not. Exit 1 otherwise, or if a self-test fails. 
 +""" 
 +from __future__ import annotations 
 + 
 +import argparse 
 +import re 
 +import sys 
 + 
 +# Attribute values are split into path segments. A segment matches a keyword 
 +# only if it equals the keyword, or the keyword plus a button/link suffix. 
 +# So "logout" and "logout-link" hit; "logout-policy", "accounting", "gravatar" 
 +# do not. Substring search of the HTML is how those three false-positived. 
 +ATTR_RE = re.compile( 
 +    r"(?:id|name|aria-label|href|data-testid|type)\s*=\s*['\"]([^'\"]+)['\"]", 
 +    re.IGNORECASE, 
 +) 
 +SUFFIXES = ("", "-link", "-btn", "-button", "_link") 
 +LOGOUT_KW = ("logout", "log-out", "signout", "sign-out", "log_out", "sign_out") 
 +USER_KW = ("account", "avatar", "user-menu", "logged-in", "logged_in") 
 +LOGIN_KW = ("login", "log-in", "signin", "sign-in", "log_in", "sign_in", "password") 
 + 
 + 
 +def segments(value: str) -> set[str]: 
 +    parts = re.split(r"[/?#&=]+", value.lower()) 
 +    out = {p.strip() for p in parts if p.strip()} 
 +    # aria-label="Log out" is one attribute, not a path. Collapse space/underscore 
 +    # to hyphen so it matches the keyword "log-out". Do not split on spaces: that 
 +    # would turn the label into the tokens "log" and "out", which are not keywords. 
 +    out.add(value.lower().replace("_", "-").replace(" ", "-")) 
 +    return out 
 + 
 + 
 +def hits(html: str, keywords: tuple[str, ...]) -> set[str]: 
 +    found: set[str] = set() 
 +    allowed = {kw + suf for kw in keywords for suf in SUFFIXES} 
 +    for m in ATTR_RE.finditer(html): 
 +        for seg in segments(m.group(1)): 
 +            if seg in allowed: 
 +                found.add(seg) 
 +    return found 
 + 
 + 
 +def markers(html: str) -> dict[str, set[str]]: 
 +    return { 
 +        "logout": hits(html, LOGOUT_KW), 
 +        "user": hits(html, USER_KW), 
 +        "login_area": hits(html, LOGIN_KW), 
 +    } 
 + 
 + 
 +LOGGED_OUT_HTML = """<!doctype html> 
 +<html><body> 
 +  <a href="/login" id="login-link">Log in</a> 
 +  <form id="login-form"> 
 +    <input type="password" name="password"> 
 +    <button type="submit">Sign in</button> 
 +  </form> 
 +  <script>sessionStorage.setItem("anon", "1")</script> 
 +</body></html> 
 +""" 
 + 
 +LOGGED_IN_HTML = """<!doctype html> 
 +<html><body> 
 +  <a href="/account" id="user-menu">alice@example.com</a> 
 +  <a href="/logout" id="logout-link">Log out</a> 
 +  <div data-testid="logged-in">signed in</div> 
 +</body></html> 
 +""" 
 + 
 +TRAP_HTML = """<!doctype html> 
 +<html><body> 
 +  <p>Your session expired. Please log out of other devices, then log in.</p> 
 +  <script>sessionStorage.clear()</script> 
 +  <a href="/login" id="login-link">Log in</a> 
 +</body></html> 
 +""" 
 + 
 + 
 +def verdict(logged_out: str, logged_in: str) -> tuple[bool, list[str]]: 
 +    """Shepherd: a method must succeed with cookies and fail without them.""" 
 +    out_m = markers(logged_out) 
 +    in_m = markers(logged_in) 
 +    reasons: list[str] = [] 
 + 
 +    logout_only_in = in_m["logout"] - out_m["logout"] 
 +    if logout_only_in: 
 +        reasons.append("logout marker present only when logged in: " + ", ".join(sorted(logout_only_in))) 
 + 
 +    user_only_in = in_m["user"] - out_m["user"] 
 +    if user_only_in: 
 +        reasons.append("user marker present only when logged in: " + ", ".join(sorted(user_only_in))) 
 + 
 +    login_only_out = out_m["login_area"] - in_m["login_area"] 
 +    if out_m["login_area"] and not in_m["login_area"] and login_only_out: 
 +        reasons.append( 
 +            "login area present logged-out and absent logged-in: " + ", ".join(sorted(login_only_out)) 
 +        ) 
 + 
 +    return bool(reasons), reasons 
 + 
 + 
 +def self_test() -> None: 
 +    failed = 0 
 + 
 +    ok, why = verdict(LOGGED_OUT_HTML, LOGGED_IN_HTML) 
 +    if not ok: 
 +        print("SELFTEST FAIL: documented pair should verify") 
 +        failed += 1 
 +    else: 
 +        print("SELFTEST ok   documented pair verifies:") 
 +        for line in why: 
 +            print("         ", line) 
 + 
 +    ok, _why = verdict(LOGGED_OUT_HTML, LOGGED_OUT_HTML) 
 +    if ok: 
 +        print("SELFTEST FAIL: two logged-out snapshots must not verify") 
 +        failed += 1 
 +    else: 
 +        print("SELFTEST ok   two logged-out snapshots do not verify") 
 + 
 +    ok, _why = verdict(TRAP_HTML, TRAP_HTML) 
 +    if ok: 
 +        print("SELFTEST FAIL: prose 'log out' must not count as a marker") 
 +        failed += 1 
 +    else: 
 +        print("SELFTEST ok   prose 'log out' / sessionStorage is not a marker") 
 + 
 +    # Substring traps the first regex version accepted. Both snapshots keep the 
 +    # login form; the candidate only adds the tempting attribute. 
 +    for name, extra in ( 
 +        ("accounting", '<a id="accounting" href="/x">ledger</a>'), 
 +        ("gravatar", '<img data-testid="gravatar" src="g.png">'), 
 +        ("logout-policy", '<a href="/logout-policy">policy</a>'), 
 +    ): 
 +        candidate = LOGGED_OUT_HTML.replace("</body>", extra + "</body>") 
 +        ok, why = verdict(LOGGED_OUT_HTML, candidate) 
 +        if ok: 
 +            print(f"SELFTEST FAIL: {name} must not verify:", why) 
 +            failed += 1 
 +        else: 
 +            print(f"SELFTEST ok   {name} is not a login marker") 
 + 
 +    # Equality, not substring: a segment "sessionid-link" is not the token "session". 
 +    session_html = '<a href="/x" id="sessionid-link">account</a>' 
 +    if "session" in hits(session_html, ("session",)): 
 +        print("SELFTEST FAIL: token equality collapsed to substring 'session'") 
 +        failed += 1 
 +    else: 
 +        print("SELFTEST ok   'sessionid-link' is not the token 'session'") 
 + 
 +    aria = LOGGED_OUT_HTML.replace( 
 +        "</body>", '<a aria-label="Log out" href="/x">leave</a></body>' 
 +    ) 
 +    ok, why = verdict(LOGGED_OUT_HTML, aria) 
 +    if not ok: 
 +        print("SELFTEST FAIL: aria-label='Log out' must verify:", why) 
 +        failed += 1 
 +    else: 
 +        print("SELFTEST ok   aria-label='Log out' is a logout marker") 
 + 
 +    if failed: 
 +        raise SystemExit(f"login_diff.py: {failed} self-test(s) failed") 
 + 
 + 
 +def main() -> int: 
 +    ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) 
 +    ap.add_argument("--logged-out", help="HTML snapshot without the candidate session") 
 +    ap.add_argument("--logged-in", help="HTML snapshot with the candidate session") 
 +    ap.add_argument("--skip-self-test", action="store_true") 
 +    args = ap.parse_args() 
 + 
 +    if not args.skip_self_test: 
 +        self_test() 
 + 
 +    if args.logged_out is None and args.logged_in is None: 
 +        logged_out = LOGGED_OUT_HTML 
 +        logged_in = LOGGED_IN_HTML 
 +        print("\nDocumented run (embedded fixtures):") 
 +    else: 
 +        if args.logged_out is None or args.logged_in is None: 
 +            ap.error("give both --logged-out and --logged-in, or neither") 
 +        logged_out = open(args.logged_out, encoding="utf-8").read() 
 +        logged_in = open(args.logged_in, encoding="utf-8").read() 
 +        print("\nRun on supplied snapshots:") 
 + 
 +    ok, why = verdict(logged_out, logged_in) 
 +    if ok: 
 +        print("VERIFIED login") 
 +        for line in why: 
 +            print("  ", line) 
 +        return 0 
 +    print("NOT VERIFIED: no marker present only in the logged-in snapshot") 
 +    print("  logged-out markers:", markers(logged_out)) 
 +    print("  logged-in markers: ", markers(logged_in)) 
 +    return 1 
 + 
 + 
 +if __name__ == "__main__": 
 +    sys.exit(main())
 </file> </file>
  
-=== Figures ===+Documented run, 2026-08-27, eight self-tests then the fixtures (path-segment equality, not substring; ''aria-label="Log out"'' counts):
  
-To use floats, you have to use the ''<WRAP>'' tag. For instance, the following will create figure on the right side 50% large: +<code> 
-<WRAP right 50% box> +SELFTEST ok   documented pair verifies: 
-{{PATH_TO_FILE|ALT_TEXT}} +          logout marker present only when logged in: logout, logout-link 
-<div>CAPTION</div> +          user marker present only when logged in: account, logged-in, user-menu 
-</WRAP>+          login area present logged-out and absent logged-in: login, login-link, password 
 +SELFTEST ok   two logged-out snapshots do not verify 
 +SELFTEST ok   prose 'log out' / sessionStorage is not a marker 
 +SELFTEST ok   accounting is not a login marker 
 +SELFTEST ok   gravatar is not a login marker 
 +SELFTEST ok   logout-policy is not a login marker 
 +SELFTEST ok   'sessionid-link' is not the token 'session' 
 +SELFTEST ok   aria-label='Log out' is a logout marker
  
-*/+Documented run (embedded fixtures): 
 +VERIFIED login 
 +   logout marker present only when logged in: logout, logout-link 
 +   user marker present only when logged in: account, logged-in, user-menu 
 +   login area present logged-out and absent logged-in: login, login-link, password 
 +</code>
  
-====== References ======+===== SSO as a way in, versus SSO as the subject =====
  
-/* +These are different papers. Using Facebook as a door into a ranked list is scale-login / scale-register. Counting OAuth buttons is an SSO study, and several of those studies **never complete** the relying-party login.
-To insert citations, follow these steps:+
  
-  - Verify the BibTeX entry exists in https://measuretheweb.org/literature/bibliography. If not, add it there. +  * **SSOScan**, Zhou and Evans, USENIX Security 2014 {[zhou2014_ssoscan]}. Quantcast, 17,913 sites after filtering; Facebook SSO on **1,660 (9.3%)**. The enrolment process succeeds for **80%** of Facebook-SSO sites in the top 10k. About **44%** of sites still require a traditional registration after SSO. Top-10k automation failures included **34 CAPTCHAs**. This is the 2014 "Zhou" the stub named; it is not old in the sense of a dead method, it is the first automated SSO enrolment crawl in this corpus. 
-  - Use {[CitationKey]} where needed in the text; it will render as a numbered reference. +  * **O Single Sign-Off**, Ghasemisharif et al., USENIX Security 2018 {[ghasemisharif2018_sso]}. Puppeteer over Alexa 1M; **912,206** processed; SSO on **57,555 (6.30%)**; Facebook 4.62% (42,232), Google 2.75% (25,142). Schema: ''none''. The RP takeover was manual. 
-  - Keep this section unchanged to display the bibliography.+  * **SSOmething**, Dimova et al., PoPETs 2023 {[dimova2023_ssomething]}. CDP crawl of CrUX 100k; OAuth buttons on **6,211 (7.23%)**; **18.53%** requested non-minimal scopes. Schema: ''none''. They did not complete RP login at scale. 
 +  * **SAAT**, Ghasemisharif, Kanich and Polakis, IEEE S&P 2022 {[ghasemisharif2022_saat]}. Facebook SSO login on **1,900** RPs; traditional-credential registration on **243**. ReCAPTCHA v2 audio via Wit.ai; Gmail API plus **Twilio SMS**; ''puppeteer-extra-plugin-stealth''. They wrote down the ToS caveat: "While this could potentially violate RPs' terms of service, automation is a widely established common practice in web security research".
  
-If any step fails, a purple warning will appear on the preview page. +A crawl that only //detects// an SSO button has not logged in. Dimova et al. are explicit about that. Do not cite 7.23% as a login rate.
-*/+
  
-<bibtex bibliography></bibtex>+The other half of these studies — SSO, MFA and passkey deployment as the //subject//, with the denominators that go with it — is [[Security:Authentication]]. This page keeps them here for the instrument caveat above; that page carries the prevalence question.
  
 +===== Automated registration =====
 +
 +Five numbers people confuse. They do not share a denominator.
 +
 +^ Paper ^ What was created ^ Of what ^ Rate ^
 +| Drakonakis et al. registered and logged in {[drakonakis2020_cookie]} | count not given | 168,594 domains with a signup option | **13.7%** |
 +| Drakonakis et al. accounts created {[drakonakis2020_cookie]} | 25,242 accounts | 168,594 signup domains | they write "almost 12%"; 25,242/168,594 is **15.0%** |
 +| Drakonakis et al., of the full crawl {[drakonakis2020_cookie]} | 25,242 accounts | 1,585,964 unique domains crawled | **~1.6%** |
 +| Al Roomi et al., USENIX Security 2023 {[alroomi2023_login]} | 45.0K initial test accounts | Google CrUX top 1M | **4.5%** |
 +| Alroomi et al., CCS 2023 {[alroomi2023_password]} | 20,119 domains fully evaluated | Tranco 1M after filtering | a completed-evaluation count, not a success rate |
 +| Kubicek et al., TheWebConf 2024 {[kubicek2024_register]} | register-or-newsletter | 660,202 unique Tranco domains | **5.9%** |
 +
 +Kubicek et al. compare themselves to Cookie Hunter's **1.6% of Alexa 1M** (the 25,242 count over the crawl), not to 13.7% of signup domains. Use the same comparison they used. Do not write "25,242 (13.7%)": 13.7% is registered-and-logged-in of signup domains; 25,242 is a separate "accounts created" count.
 +
 +**Cookie Hunter.** XDriver on Selenium. Email verification by visiting links in mail. SMS / SSN blocked leftover of the top 1K, completed by hand; the ~25K that make the evaluation "did not require any manual intervention". reCAPTCHA on 19,491 (~13.8%) of signup domains. They tried an audio-reCAPTCHA solver; Google was not serving captchas to WebDriver. They **did not** pay a farm {[drakonakis2020_cookie]}:
 +
 +> funding human captcha-solving services to create accounts presents an ethical dilemma, we opted to not handle such cases.
 +
 +**Login policies** (Al Roomi and Li) {[alroomi2023_login]}. CrUX 1M (they started ground-truth on Tranco and switched because CrUX is websites). Signup page on 258,200 domains; **45.0K** initial accounts; a second account on only 37,300. AZcaptcha. In the **ground-truth** accounts they created by hand, 39% of domains sent a verification email — that 39% is **not** of the 45.0K. They did not complete phone verification.
 +
 +**Password policies** (Alroomi and Li) {[alroomi2023_password]}. Tranco 1M; **20,119** domains fully evaluated. CAPTCHAs on at least **49%** of signup forms; AZcaptcha solved **94%**. They avoided human-driven solvers "due to ethical issues identified with such services", and they "are unable to explicitly check" terms of service at this scale.
 +
 +**Tripwire** {[deblasio2017_tripwire]}. Honey accounts to infer site compromise from password reuse. **65,413** registration attempts across **33,634** sites; **3,664** accounts on around **2,302** sites. Third-party CAPTCHA solver (DeCaptcher). "While we make no attempt to explicitly check the terms of service".
 +
 +**Kubicek et al.** {[kubicek2024_register]}, author PDF. Tranco list ''82Q3V'', June 2022. A processing error sampled one million domains **with replacement**, so the results are **660,202 unique** domains. Loaded 504,509 of those. Form on **25.7% (169,765)** of the **660,202** unique domains — the PDF writes this "among the loaded websites"; 169,765 of 504,509 loaded is 33.7%, so the printed 25.7% is the unique-domain rate. Form-submit estimated success **30.2% (51,290)**, fail 38.4%, unknown 31.4%. Headline **5.9%** register-or-newsletter. CrUX overlap 51.9%; load 90.6% vs 65.3% non-CrUX; "successful registration" 11.7% CrUX vs 3.9% non-CrUX. Selenium + Chrome, 60 parallel Docker containers, 12 German Research Network IPs, unique email per site at ''sybilmail.de''. CAPTCHA on **one-third**; of those, **75% reCAPTCHA v2, 20% v3, 2% hCaptcha, 3% image**. They used a **human CAPTCHA farm**, discussed it with their legal department, and later switched to research assistants. The crawler is **not public** (bomb-attack risk); access is by request at ''https://karelkubicek.github.io/post/reg-www''. 37.2% (12,605) marketing without proper consent; 1.8% email shared with undeclared third parties; 59.8% fail double opt-in. They do not do SSO registration.
 +
 +===== Newsletter =====
 +
 +A mailing-list form is not an account. Coverage is higher, legal exposure is different, and you still have to say which one you did.
 +
 +Englehardt, Han and Narayanan {[englehardt2018_email]}: OpenWPM; 15,700 sites visited; forms attempted on 3,335; of a sample of **252**, **38%** successful submit and **16%** failed for a CAPTCHA; 12,618 emails from 902 senders. Schema: ''none''.
 +
 +Kubíček et al. {[kubicek2022_emails]}: human annotators; **666 of 1,000** registered; more than 5,000 emails. Pair these two sentences from the same paragraph, and do not paste the abstract's 59% onto the 666:
 +
 +> Only 59% of websites that sent us at least one email first sent us a double opt-in email. Moreover, 5.5% of services sent us an unsolicited marketing email without any confirmation or double opt-in email.
 +
 +The 59% is of websites that sent mail. The 5.5% is of services that sent unsolicited marketing with no confirmation. Neither is "59% of 666".
 +
 +Mathur et al. {[mathur2023_political]}: Big Data & Society 2023, **outside this corpus**. 300K political emails from the 2020 US cycle, built on Englehardt's OpenWPM signup bot. Kubicek et al. cite the 2020 project page; the journal version is the citable record.
 +
 +===== Forms without submit =====
 +
 +Senol et al. {[senol2022_leaky]} filled email on **52,055** of **99,380** loaded Tranco 100k sites (EU, no-action) and left. Schema: ''none''. How they typed — randomised key intervals, not ''input.value'' — is on [[Programming:Interaction]]. Playwright's ''locator.pressSequentially()'' versus ''fill()'' is there too.
 +
 +Chatzimpyrros, Solomos and Ioannidis {[chatzimpyrros2020_register]}: ESORICS workshop, LNCS 2020, **outside this corpus**. ~200,000 sites; about 5% leaked PII from registration forms without submit.
 +
 +===== CAPTCHA, email, SMS — dated =====
 +
 +CAPTCHA is **non-random loss**. Cookie Hunter's 22 unsolved anti-bot cases, quoted on [[Programming:Interaction]], are the same observation: the sites that block you are not a random sample of sites.
 +
 +^ When ^ What the measurement papers actually used ^ Status in 2026 ^
 +| 2017 (Tripwire) | third-party solver (DeCaptcher); could not handle then-modern reCAPTCHA | Historical. The solver market still exists; this product is not the one to name as current |
 +| 2020 (Cookie Hunter) | no farm; WebDriver already made Google not serve reCAPTCHA | The ethical refusal is still the argument to cite. The detection of WebDriver is not the 2026 bottleneck |
 +| 2022 crawl (Kubicek et al., published 2024) | human farm; mix **75 / 20 / 2 / 3** v2 / v3 / hCaptcha / image; later, research assistants | Dated snapshot of **what was on the web in 2022**. Not a 2026 vendor share |
 +| 2023 (Alroomi / Al Roomi) | AZcaptcha, described in those papers as OCR not humans; 94% solve rate on the password-policy crawl | **Paper-era** automated farm-API. They avoided human solvers on purpose. Live AZcaptcha docs (fetched 2026-08-27) mention a workers pool — do not treat the 2023 OCR claim as a 2026 service description |
 +| 2023 (Searles et al.) {[searles2023_captcha]} | **manual** user study, 1,400 people, 14,000 CAPTCHAs; 185 of ~200 Alexa sites had account creation, **142** succeeded | Not a crawler. Useful for "will a human complete signup" |
 +| 2025 (Teoh et al., Halligan) {[teoh2025_captcha]} | agentic VLM **60.7%** of 2,600 challenges; infiltrated **2Captcha** at **70.6%** | **Current.** Farms still exist in 2025. VLMs change the "unsolvable CAPTCHA" story; they do not end it |
 +| 2026 (Turnstile) | Cloudflare's CAPTCHA-free widget: Managed / Non-interactive / Invisible; hosted at ''challenges.cloudflare.com''; WCAG 2.2 AA | **Current, and almost absent from this corpus.** Docs last updated 2026-08-14 (overview) and 2026-04-16 (widget types), fetched 2026-08-27. A 2022 crawl's 75% v2 mix will not describe a 2026 sample |
 +
 +Do not take a share from Similarweb, wmtips, or any SEO page. The 75/20/2/3 mix is Kubicek et al.'s 2022 crawl. Google's reCAPTCHA landing page (''https://developers.google.com/recaptcha'') still returns HTTP 200 (2026-08-27) but is **deprecated**; the replacement is Google Cloud Fraud Defense (''https://cloud.google.com/recaptcha/docs/overview'', HTTP 200: "reCAPTCHA has become a part of Google Cloud Fraud Defense"). hCaptcha's docs also serve. Turnstile is the one that changed the "show a puzzle" default.
 +
 +Email verification is the common path (login-policies ground-truth 39%; Cookie Hunter visited the link). SMS is the expensive path: SAAT used Twilio; Cookie Hunter treated phone/SSN as a leftover for the top 1K; login-policies did not do phone. Plan for email. Budget SMS only if the research question lives behind it.
 +
 +Human CAPTCHA farms: **name who used them, and when**. Cookie Hunter no; Kubicek et al. yes then research assistants; Tripwire used DeCaptcher (a third-party solver; the paper does not establish that the solvers were human); password-policies AZcaptcha, described there as not human, on purpose; Teoh et al. infiltrated 2Captcha in 2025 as an experiment, not as a measurement instrument they recommend. Do not present a farm as current best practice.
 +
 +===== Terms of service and ethics =====
 +
 +The ethics page already ranks what crawling papers say they did. Of 697 papers that describe a mitigation, **92 (13.2%)** mention test accounts or synthetic identities, and **17 (2.4%)** mention robots.txt, terms of service or acceptable-use policies. A full-text sweep on the same 1,120 crawling papers finds 129 (11.5%) that mention terms of service at all — without separating "we complied" from "the site's ToS prohibits X". This page does not re-derive those figures. See [[Practices:Ethics]].
 +
 +What the registration papers themselves wrote:
 +
 +  * Tripwire {[deblasio2017_tripwire]}: "While we make no attempt to explicitly check the terms of service".
 +  * Password policies {[alroomi2023_password]}: consulted general counsel; "unable to explicitly check" ToS at this scale; avoided human CAPTCHA solvers.
 +  * SAAT {[ghasemisharif2022_saat]}: named the ToS tension and did it anyway, as "widely established common practice".
 +  * Cookie Hunter {[drakonakis2020_cookie]}: the farm was the ethical line they would not cross; they still created 25,242 accounts.
 +  * Kubicek et al. {[kubicek2024_register]}: legal review, farm conditions discussed with the university legal department, crawler withheld because it is a bomb-attack tool.
 +
 +There is no consensus in this literature that creating test accounts is permitted, forbidden, or ToS-exempt. The papers that created accounts at this scale wrote that they did **not** check ToS (Tripwire, password-policies) or named the tension and did it anyway (SAAT). That is five papers, not a vote of 45.0K. Write the sentence: synthetic identities, unique emails, whether you solved CAPTCHAs and how, whether you completed email/SMS, and that you did not check ToS at scale (if you did not). [[Practices:Ethics]] is the page for robots.txt and for the network acceptable-use policy that will actually stop you.
 +
 +===== Which methods are current =====
 +
 +^ Method ^ Status ^
 +| Logged-out crawl of a ranked list | **Still the default, and still defensible** for questions that do not live behind an account. 553/857 are labelled ''none'' |
 +| Manual accounts, then scripted login (Kaizer 2016, To Auth 2024) | **Current** when the list is hundreds, not hundreds of thousands |
 +| Shepherd-style differential verification | **Current, and underused.** The 2020 workshop paper is out of corpus; the method is not obsolete |
 +| Cookie Hunter-style full registration on a million-site list | **Done, expensive, and CAPTCHA-censored.** The 13.7% is registered-and-logged-in of signup domains in 2020, under a no-farm constraint; the 25,242 is a separate accounts-created count |
 +| Human CAPTCHA farm as a measurement instrument | **Used (Kubicek 2022 crawl). Not best practice.** Tripwire 2015 used a third-party solver, not established as a human farm. Password-policies 2023 and Cookie Hunter 2020 both refused a human farm. Teoh 2025 shows the farm is still there to infiltrate |
 +| AZcaptcha / automated solver APIs | **Used in the 2023 policy crawls.** Date the OCR/not-humans claim to those papers; live AZcaptcha docs (fetched 2026-08-27) mention a workers pool |
 +| Agentic VLM solving (Halligan 2025) | **New.** 60.7% is a paper about whether the technique works, which is the stage it is at |
 +| Turnstile / CAPTCHA-free widgets | **Current on the web, almost unmeasured in this corpus.** Date any CAPTCHA-mix figure |
 +| Newsletter signup | **Current** as a lighter instrument; say it is not an account |
 +| Fill without submit | **Current** for exfiltration; not a login |
 +| SSO as a door into a ranked list | **Rare.** Schema SSO among web crawls is 0. SAAT and SSOScan did it; Dimova and Ghasemisharif 2018 measured SSO without completing RP login at scale |
 +
 +===== What to report =====
 +
 +A methods paragraph that answers these is enough. None of them takes more than a clause.
 +
 +  - **Which of the four jobs** you did (login / register / newsletter / fill-without-submit).
 +  - **How many accounts, of how many sites that offered the form, of how many sites you tried.** Three numbers, not one rate.
 +  - **How you verified login** — differential (Shepherd), identifier in the page, session cookie still set on a second visit. "HTTP 200 after POST" is not a verification.
 +  - **CAPTCHA**: which providers you saw, whether you solved, automated API or human or VLM or not at all, and that this censors the sample.
 +  - **Email and SMS**: unique addresses? visited the link? phone numbers? Twilio?
 +  - **ToS / ethics**: test accounts, whether you checked ToS (usually: you did not, at this scale), IRB/legal if you have it.
 +  - **SSO**: did you complete the RP login, or only count buttons?
 +
 +===== Methodology and limitations =====
 +
 +Corpus: 5,859 extracted papers, 2010–2026, CCS, IMC, NDSS, PETS, USENIX Security, TheWebConf, IEEE S&P. Population for every share on this page is the 857 web crawls unless a sentence names another. 2025–2026 venue-years are incomplete by construction; tables that include them are starred.
 +
 +The 81 is a schema enum; the 17 is a hand map over those 81 (''scripts/registration_fold.mjs'') checked both ways at run time by ''scripts/report_registration.mjs''. It is not a full-text census of the 776 papers the schema did not mark as logged in. A missing ROLE or a stale ROLE key prints ''FAILURE'' and exits 1. Loose full-text sweeps for "register" and "shepherd" are homograph-dominated and were not used as counts.
 +
 +Out of corpus, and labelled so wherever they appear: Shepherd (MADWeb 2020), Chatzimpyrros et al. (ESORICS workshop), Mathur et al. (Big Data & Society). In the bibliographic index but not extracted: Kubicek et al. WWW 2024.
 +
 +The query log, the ROLE list, the rejected sweeps, and the review log are on [[provenance:programming:registration]]. Corpus-level caveats are on [[literature:corpus]].
 +
 +===== Open questions =====
 +
 +<WRAP todo>
 +  * Re-extract Kubicek et al. WWW 2024 so its figures sit in ''paper.cols.txt'' like every other paper this page cites from the corpus.
 +  * A 2026 CAPTCHA-provider mix on CrUX or Tranco, with Turnstile as a first-class label. The 75/20/2/3 snapshot is 2022.
 +  * How often a Shepherd-style verifier disagrees with "the login form disappeared".
 +  * A hand split of the 129 crawling papers that mention terms of service into "we complied" versus "the ToS of the thing we studied".
 +</WRAP>
 +
 +===== Related pages =====
 +
 +  * [[Programming:Interaction]] — depth, typing versus ''fill()'', the logged-out default as a coverage problem
 +  * [[Privacy:PII leakage]] — what leaves once the form is filled: canary identities, the encoding search, and the ethics of synthetic PII
 +  * [[Programming:Stateful Stateless]] — the profile that login writes into
 +  * [[Privacy:Consent]] — the banner in front of the form
 +  * [[Practices:Ethics]] — robots.txt, test accounts, ToS as a harm-mitigation family
 +  * [[Programming:Crawler]] — the library that clicks the button
 +  * [[Programming:Tranco]] — pinning the list id (Kubicek et al. used ''82Q3V'')
 +
 +====== References ======
 +
 +<bibtex bibliography></bibtex>
  
-/* This enables discussion under this article. */ 
 ~~DISCUSSION~~ ~~DISCUSSION~~
 +
programming/registration.1739892438.txt.gz · Last modified: by karelkubicek