User Tools

Site Tools


programming:registration

Differences

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

Link to this comparison view

Next revision
Previous revision
programming:registration [2025/02/18 15:26] – created brainstorming page karelkubicekprogramming:registration [2026/08/27 13:08] (current) – Apply focused+generic review: split Cookie Hunter 13.7% vs 25,242; Kubicek 25.7% of unique domains; login_diff segment match and aria-label; recaptcha deprecation; no ToS-consensus claim. Authored by Claude karel.kubicek.claude
Line 1: Line 1:
 ====== Automating Login and Registration to Websites ====== ====== Automating Login and Registration to Websites ======
  
-WiPbrainstorming 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 baglab 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 subpageDepth, 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 measurementsreferences 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 registration3,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 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.
  
-  * Automated interaction wit hforms but without submission: Senol et al(2022) and Chatzimpyrros et al. (2019) +^ Role ^ Papers ^ Share of 81 ^ What it is ^ 
-/+| scale-register | 8 | 9.9% | automated account creation on the sites being measured | 
-This is comment not visible on the pageIt outlines the syntax (for morego to https://measuretheweb.org/wiki/syntax), especially that related to bibliography. Remove it once you created the pageIf you use any citations (documented at bottom), keep the References section.+| 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% | 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 phenomenonnot 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 accountsnot a ranked-list login crawl | 
 +| mislabel | 11 | 13.6% | did not authenticate to the sites they measured |
  
-===== Header Level 2 ===== +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).
-==== Header Level 3 ====+
  
-=== Links ===+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.
  
-External links are recognized automatically: www.google.combut if you want a link text: [[http://www.google.com|This Link points to google]].+The 17 instrument papersin year orderSSOScan {[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.
  
-Internal links are created by using square brackets. You can either just give a [[pagename]] or use an additional [[pagename|link text]].+Year shape of the 17, of web crawls in that bucket2025–2026 is provisional:
  
-=== Lists ===+^ 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 and their levels are decided by indentation (2 spaces 1 level)+===== Automated login =====
  
-  - this is 1item +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 skipShepherd 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 themThree checks: a logout button or user identifier after submit; the same on the landing page; an attempt to re-open the login area (which well-designed site should refuse)Verification accuracy on a 100-site sample was ≥97%.
-  - 2item +
- nested a. item +
-  * bullet-point item+
  
-=== Code ===+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.
  
-For a short inline monospace, use ''double quote''For proper code (but in a separate paragraph)use ''<code LANG>'':+Calzavara et al{[calzavara2014_cookiejar]} is the other half of the login problem: once you are in, **which cookies are the session**. They built gold set from 70 Alexa sites; a naïve script was wrong on 2 of 70. That is identificationnot login.
  
-<code python> +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. 
-string = "World+ 
-print(f'Hello {string}') +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. 
-</code>+ 
 +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 python login_diff.py
 +#!/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: {namemust 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
  
-For large code, use ''<file LANG filename>'', it will make code downloadable. For instance: 
  
-<file php example.php> +if __name__ == "__main__"
-<?php echo "hello world!"; ?>+    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 instancethe 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: logoutlogout-link 
-<div>CAPTION</div> +          user marker present only when logged inaccount, 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 studyand several of those studies **never complete** the relying-party login.
-To insert citationsfollow these steps:+
  
-  - Verify the BibTeX entry exists in https://measuretheweb.org/literature/bibliographyIf 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 10kAbout **44%** of sites still require a traditional registration after SSOTop-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 textit 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, 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 login rate.
-*/+
  
-<bibtex bibliography></bibtex>+===== 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
 +  * [[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.1739892385.txt.gz · Last modified: by karelkubicek

Except where otherwise noted, content on this wiki is licensed under the following license: CC BY-NC-SA 4.0
CC BY-NC-SA 4.0 Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki