Attackers want your data and they're getting it from your API

Tim Bond

Longhorn PHP Conference - October 15, 2021

Who am I?

  • PHP developer
  • API developer
  • API connoisseur
  • Frontend developer
    (when I have to be)
  • Cyclocross racer

Who am I NOT?

  • Lawyer
  • Security expert
  • Penetration tester
  • Knower of everything
  • Cat 1 cyclocross racer

What is this talk?

  • Things I've seen
  • Things I can talk about
  • More about mobile apps than web apps
  • Somewhat applicable to M2M apps

What is this talk NOT?

  • A hacking workshop
  • The answer to every question
  • The only thing you should consider
  • Really about "public" APIs (e.g. Stripe, Twilio)
  • Going to have any more cyclocross references

Why attack an API?

  • Curiosity/data mining
  • Espionage or "competitor analysis"
  • Grudge
  • No other way to get data
  • Want to build their own frontend
  • API key application was rejected
  • Automation

'Automating' comes from the roots 'auto-' meaning 'self-', and 'mating', meaning 'screwing'.

Image credit: XKCD "Automation", licensed Creative Commons Attribution-NonCommercial 2.5

TL;DR:

  • Limit your API responses
    • Only the data you need to make the app work
  • Only to the user that needs to see it
  • Only provide endpoints for what your customers need
    • Do you really need an endpoint that lists all users?
    • Or could you scope it to specific roles/permissions?
  • KISS - Every flag adds another permuatation

Code bugs > everything else

  • Google+ breach in November 2018
  • 52.5 million users
    • Name
    • Email address
    • Occupation
    • Gender
    • Age

Write tests!

  • Test every endpoint:
    • Authenticated
    • Unauthenticated
    • Every role
    • Every query string param

The low-hanging fruit

  • SQL injection
  • XSS
  • DDoS
    • Large payloads

Obscurity != Security

Let's hack it!

  1. Set up a packet sniffer

Packet Capture

Let's hack it!

  1. Set up a packet sniffer
    • Counter measure: use HTTPS
  2. Set up a Man-In-The-Middle attack
    • Counter measure: use certificate pinning
  3. Bypass certificate pinning

Let's hack it!

  1. Set up a packet sniffer
    • Counter measure: use HTTPS
  2. Set up a Man-In-The-Middle attack
    • Counter measure: use certificate pinning
  3. Bypass certificate pinning
    • Counter measure: none...?
    • Maybe: check for root

Let's hack it!

GET http://api.example.com/items
POST http://api.example.com/analytics
PUT http://api.example.com/scan/498044355635
POST http://api.example.com/analytics

Look at the payload: GET /items

[
    {
        "title": "Bleach",
        "upc": 498044355635,
        "scanned": false
    },
    // more items
]

Look at the payload: PUT /scan/nnn

{
    "user_id": 1234,
    "latitude": 30.3235,
    "longitude": -97.7109
}

How can we hack it?

  • API has no authentication 🥳
  • There are some analytics, but we can probably ignore that
  • Upon opening the app, we get a list of all the products
    • Just iterate over that list and send 10 PUT requests
    • Put it in a cron job and you'll have a coupon every time you shop
    • Set it up for your friends (just get their ID)

Let's keep exploring the API

  • Try some other routes
    • It looks RESTful, so how about /user/123
    • Or /users
  • Are there docs?  Head to /docs to find out
  • Let's try something we know doesn't exist, and see if we get a stack trace

A case for UUIDs

  • /users/123
    • /users/124
  • /users/FA091B58-B0E8-46E9-8DEE-592EBA4D62C4
    • ??

Maybe it's time for some auth

  • Auth Basic
  • Auth Digest
  • RFC 2069 Digest Access Authentication Syntax

    Hash1=MD5(username:realm:password)
    Hash2=MD5(method:digestURI)
    response=MD5(Hash1:nonce:Hash2)
    

Maybe it's time for some auth

  • API keys?
    • Partner/User API keys
    • Application API keys
  • NEVER use static API keys
    • Compromised as soon as they're used
    • Generally easy to find in the source code
    • Hard to rotate

Want a key?  Check GitHub!

Maybe it's time for some auth

  • JWT

Maybe it's time for some auth

  • JWT
    • Know exactly who is making the request
      • Can assign to known users and unknown
    • Time limited
    • Can't revoke one
      • But you can revoke them all

What people say...

What it actually looks like

Don't give access to everything

👈 No access to Purchase API

Let 'em sniff, but kill repeatability

  • HMAC
  • Gather the payload and sign the request

Signed

GET /users/123

API_KEY = NWTPk4

APP_ID = wQrDfM

Unsigned

GET /users/123

API_KEY = NWTPk4

APP_ID = wQrDfM

HMAC = APvNwF

🔒

Getting the signing key

  • Look around the app source for a key
  • See if the app logs to a console
    • Browser console on web
    • deviceconsole on iOS
    • logcat on Android

Make the signing key dynamic

  • Much more difficult to find in code
  • Must be deterministic so server can duplicate

Example: concatenate:

  • The string length of some class name
  • The app version number
  • The UTC date + hour

Reverse engineering the runtime

  • Connect the app to a debugger
  • Decompile the Android app
    • Banjo
    • dex2jar
    • JADX
    • JD-GUI
    • baksmali
  • Works on iOS too--ask the jailbreakers

Proxify the APIs

  • App only uses one secret
  • Proxy verifies that secret
  • Proxy reaches out to the actual APIs on the user's behalf
    • Much easier to rotate API auth for 3rd party systems
  • But we're still dealing with a secret 😕

Secrets as a Service

API

Shared secret

Unauthenticated request

Secret token

API call ✅

Dynamic

Integrity
Check

Using OAuth 2

API 1

API
Gateway

Authorization request

Auth token

App Auth request

App token

OAuth 2 service

App auth service

API calls

Registered

app info

Registered

user info

API 2

API 3

Key 3

Key 1

Key 2

OAuth 2 flow

  • Authorize both who (user) and what (app)
  • Only time-limited, runtime tokens
  • Don't think of OAuth2 as user authit's an access token generator
  • Rotate secrets without touching devices
  • API gateway does rate limiting and authentication

What about endpoints that can't have authentication?

  • Rate limiting

What about endpoints that can't have authentication?

  • Rate limiting
  • Monitoring
  • Heuristics
    • IP
    • User agent
    • Time between requests
    • Geo data
  • Your API gateway might do this for you!

No API?  No problem!

No API?  No problem!

<?php
$crawler = $client->get('https://www.example.com/log-in');
$crawler->filter('#email')->sendKeys('tim.bond');
$crawler->filter('#password')->sendKeys('test123');
$crawler->filter('#log-in')->click();
$client->waitForStaleness('#log-in');

$client->waitFor('#price')->filter('#price')->getText();

But we have a CAPTCHA!

  • Dozens of services will solve those
  • Images recognized with OCR/AI and/or Humans

Conclusion

  • If they want it bad enough they will try hard enough
  • Don't use static authentication
  • Don't build your own authentication
  • Debug protection and code obfuscation thwart semi-determined attackers
  • Authenticate the app (environment) as well as the user

Questions

Attackers want your data and they're getting it from your API [Longhorn PHP]

By Tim Bond

Attackers want your data and they're getting it from your API [Longhorn PHP]

Longhorn PHP Conference - October 15, 2021

  • 88