โบ State Continuation (ะฝะต ะฟััะฐัั ั CSRF state ะฟะฐัะฐะผะตััะพะผ) โ ััะพ ะผะตั ะฐะฝะธะทะผ ะทะฐัะธัั ะพั ะฟะพะดะดะตะปะบะธ/ะฟะพะฒัะพัะฐ ะทะฐะฟัะพัะพะฒ ะฒ OAuth2-ะฟะพะดะพะฑะฝัั ะฟะพัะพะบะฐั , ะพัะพะฑะตะฝะฝะพ ะฟัะธ ะพะฑะผะตะฝะต refresh token ะฝะฐ access token.
ะคะพัะผะฐะปัะฝะฐั ะผะพะดะตะปั
- ะฃะณัะพะทะฐ
ะะปะพัะผััะปะตะฝะฝะธะบ ะฟะตัะตั ะฒะฐััะฒะฐะตั ะทะฐะฟัะพั ะฝะฐ ะพะฑะผะตะฝ ัะพะบะตะฝะฐะผะธ ะธ:
- ะะพะดะผะตะฝัะตั grant_type, client_id, scope
- ะะพะฒัะพััะตั ััะฐััะน ะทะฐะฟัะพั (replay attack)
- ะะพะดะธัะธัะธััะตั claims (ะฝะฐะฟัะธะผะตั,UID, email)
- ะะฐัะธัะฐ ัะตัะตะท State Continuion
A. ะคะฐะทะฐ ะธะฝะธัะธะฐะปะธะทะฐัะธะธ (AuthManager โ AccountManager)
Client โ AccountManager.getAuthToken(account, scope, null)
ะะตะฝะตัะฐัะธั state: state = HMAC-SHA256( key = device_secret, data = { "account_id": account_id, "scope_hash": SHA256(scope_string), "timestamp": now(), "nonce": random(128bits) } )
State ะฟะตัะตะดะฐัััั ะบะฐะบ opaque ะฟะฐัะฐะผะตัั ะฒ Intent extras.
B. ะคะฐะทะฐ ะพะฑะผะตะฝะฐ (ChimeraGetToken.smali)
ะะฐะฟัะพั ะฝะฐ /token ะฒะบะปััะฐะตั: POST /token { "grant_type": "refresh_token", "refresh_token": "...", "client_id": "...", "scope": "...", "state": "<ัะณะตะฝะตัะธัะพะฒะฐะฝะฝัะน state>" # โ ะะะฎะงะะะะ ะฟะฐัะฐะผะตัั }
- ะะฐะปะธะดะฐัะธั State ะฝะฐ ัะตัะฒะตัะต
ะกะตัะฒะตั (ะฒ ะบะพะฝัะตะบััะต Google โ Google Play Services) ั ัะฐะฝะธั expected_state ะดะปั:
- ะะฐัั (account_id, scope)
- ะะพะฝะบัะตัะฝะพะณะพ nonce
- ะขะฐะนะผััะตะนะผะฐ (ะพะฑััะฝะพ ยฑ5 ะผะธะฝัั)
ะัะพะฒะตัะบะฐ: def validate_state(received_state, account_id, scope): # 1. ะัะพะฒะตััะตะผ ะฟะพะดะฟะธัั if not HMAC-SHA256(device_secret, payload) == received_state: return ERROR_INVALID_SIGNATURE
# 2. ะัะพะฒะตััะตะผ ะฐะบััะฐะปัะฝะพััั (one-time use)
if state_already_used(received_state.nonce):
return ERROR_STATE_REPLAYED
# 3. ะัะพะฒะตััะตะผ scope (ะฝะต ัะฐััะธัะตะฝ ะปะธ ะฑะตะท ะฟะพะดัะฒะตัะถะดะตะฝะธั)
if scope_hash != received_state.scope_hash:
return ERROR_SCOPE_MISMATCH
# 4. ะะพะผะตัะฐะตะผ nonce ะบะฐะบ ะธัะฟะพะปัะทะพะฒะฐะฝะฝัะน (idempotency key)
mark_state_used(received_state.nonce)
return VALID
- ะะฐัะธัะฐ ะพั ะบะพะฝะบัะตัะฝัั ะฐัะฐะบ
โโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ ะัะฐะบะฐ โ ะะตะท state continuation โ ะก state continuation โ โโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ Replay โ ะัะธะฝัั ััะฐััะน ัะพะบะตะฝ โ nonce ัะถะต ะฟะพะผะตัะตะฝ โ ะพัะบะปะพะฝัะฝ โ โโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ Scope escalation โ ะะพะถะฝะพ ะดะพะฑะฐะฒะธัั https://www.googleapis.com/auth/youtube.upload โ scope_hash ะฝะต ัะพะฒะฟะฐะดัั โ ะพัะบะปะพะฝัะฝ โ โโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ Account substitution โ ะะพะถะฝะพ ะธัะฟะพะปัะทะพะฒะฐัั token ะดััะณะพะณะพ ะฐะบะบะฐัะฝัะฐ โ account_id ะฒ HMAC โ received โ ะพัะบะปะพะฝัะฝ โ โโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ MITM modification โ ะะพะดะผะตะฝะฐ grant_type โ HMAC-ะฟะพะดะฟะธัั ะฝะตะฒะฐะปะธะดะฝะฐ โ ะพัะบะปะพะฝัะฝ โ โโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- ะัะธะฟัะพะณัะฐัะธัะตัะบะธะต ะพัะฝะพะฒั
State = HMAC-SHA256(K, M) ะณะดะต:
- K = device secret (ะฟัะธะฒัะทะฐะฝ ะบ SafetyNet/KeyStore, ะฝะตะดะพัััะฟะตะฝ ะฟะพะปัะทะพะฒะฐัะตะปั)
- M = account_id || scope_hash || timestamp || nonce
Security properties:
- Unforgeability: ะะตะท ะทะฝะฐะฝะธั K ะฝะตะปัะทั ัะณะตะฝะตัะธัะพะฒะฐัั ะฒะฐะปะธะดะฝัะน state
- Binding: State ะฟัะธะฒัะทะฐะฝ ะบ ะบะพะฝะบัะตัะฝะพะผั account_id ะธ scope
- One-time use: nonce ั ัะฐะฝะธััั ะฒ persistent storage (Keystore/SharedPreferences)
- Freshness: timestamp ะพะณัะฐะฝะธัะตะฝ (TLL ~15 ะผะธะฝ)
- ะัะธะผะตั ะธะท APK (cre.smali โ TokenWorkflow)
invoke-virtual {v0, v1, v2}, Lcom/google/android/gms/auth/TokenWorkflowClient;->getTokenWithState( Landroid/accounts/Account; [Ljava/lang/String; Landroid/os/Bundle; )
bundle.putByteArray("state", generated_state) bundle.putString("caller_package", package_name) bundle.putLong("timestamp", System.currentTimeMillis())
ะะฐ ััะพัะพะฝะต ัะตัะฒะตัะฐ (ChimeraGetToken): // ะะฐะปะธะดะฐัะธั if (!stateValidator.validate(state, account, scope)) { throw new SecurityException("State verification failed"); }
- ะะพะดะตะปั ัะณัะพะท (STRIDE)
โโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ ะฃะณัะพะทะฐ โ ะะฐะบ ะทะฐัะธัะฐะตั state โ โโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ Spoofing โ HMAC ั ััััะพะนััะฒะตะฝะฝะพ-ะฟัะธะฒัะทะฐะฝะฝัะผ ะบะปััะพะผ โ โโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ Tampering โ ะัะฑะฐั ะผะพะดะธัะธะบะฐัะธั payload ะปะพะผะฐะตั HMAC โ โโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ Repudiation โ State ะฟัะธะฒัะทะฐะฝ ะบ account_id + nonce ะปะพะณะธััะตััั โ โโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ Information Disclosure โ State = ciphertext, ะฝะต ัะพะดะตัะถะธั raw ะดะฐะฝะฝัั โ โโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ Denial of Service โ Nonce-ะบัั ะพะณัะฐะฝะธัะตะฝ ะฟะพ ัะฐะทะผะตัั (LRU) โ โโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ Elevation of Privilege โ Scope mismatch ะฟัะพะฒะตััะตััั ัะฒะฝะพ โ โโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- ะกัะฐะฒะฝะตะฝะธะต ั CSRF-state
โโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ CSRF state (web) โ State continuation (mobile) โ โโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ ะฆะตะปั โ ะะฐัะธัะฐ ะพั cross-site request โ ะะฐัะธัะฐ ะพั replay + scope escalation โ โโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ ะฅัะฐะฝะตะฝะธะต โ Cookie/session โ Keystore/device secret โ โโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ Transfer โ Form hidden field / header โ Intent extras / HTTP body โ โโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ Validation โ Session equality โ HMAC equality + nonce check โ โโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
ะะพัะพัะบะพ: State continuation = HMAC(device_secret, account+scope+nonce) ะฟัะธะฒัะทะฐะฝะฝัะน ะบ ััััะพะนััะฒั, ะพะดะฝะพัะฐะทะพะฒัะน, ั ะพะณัะฐะฝะธัะตะฝะธะตะผ ะฟะพ ะฒัะตะผะตะฝะธ. ะะพะผะฐะตั replay, scope escalation ะธ account substitution ะฐัะฐะบะธ ัะตัะตะท ะฝะตะฒะพะทะผะพะถะฝะพััั ะฟะพะดะฟะธัะธ ะฑะตะท device secret.