Slide 1

Slide 1 text

@jessewilson https://square.github.io/okhttp/ HTTP in a Hostile World

Slide 2

Slide 2 text

HTTP? • Web Pages • Web Resources (images!) • Downloads • Web APIs • Mobile APIs • Server APIs • Core Networking APIs (DNS) • Pretty much all networking ever

Slide 3

Slide 3 text

POST /pizza HTTP/1.1 host: pizza.app content-length: 50 content-type: application/json; charset=UTF-8 {x "size": "large", "toppings": ["pineapple"] }x

Slide 4

Slide 4 text

POST /pizza HTTP/1.1 host: pizza.app content-length: 50 content-type: application/json; charset=UTF-8 {x "size": "large", "toppings": ["pineapple"] }x Request

Slide 5

Slide 5 text

POST /pizza HTTP/1.1 host: pizza.app content-length: 50 content-type: application/json; charset=UTF-8 {x "size": "large", "toppings": ["pineapple"] }x URL

Slide 6

Slide 6 text

POST /pizza HTTP/1.1 host: pizza.app content-length: 50 content-type: application/json; charset=UTF-8 {x "size": "large", "toppings": ["pineapple"] }x Headers

Slide 7

Slide 7 text

POST /pizza HTTP/1.1 host: pizza.app content-length: 50 content-type: application/json; charset=UTF-8 {x "size": "large", "toppings": ["pineapple"] }x Body

Slide 8

Slide 8 text

POST /pizza HTTP/1.1 host: pizza.app content-length: 50 content-type: application/json; charset=UTF-8 {x "size": "large", "toppings": ["pineapple"] }x HTTP/1.1 200 OK content-length: 21 
 content-type: application/json; charset=UTF-8 {x "time": “30m", "price": 15.00 }x Response

Slide 9

Slide 9 text

HTTP/1.1 200 OK content-length: 21 
 content-type: application/json; charset=UTF-8 {x "time": “30m", "price": 15.00 }x POST /pizza HTTP/1.1 host: pizza.app content-length: 50 content-type: application/json; charset=UTF-8 {x "size": "large", "toppings": ["pineapple"] }x Status

Slide 10

Slide 10 text

HTTP/1.1 200 OK content-length: 21 
 content-type: application/json; charset=UTF-8 {x "time": “30m", "price": 15.00 }x POST /pizza HTTP/1.1 host: pizza.app content-length: 50 content-type: application/json; charset=UTF-8 {x "size": "large", "toppings": ["pineapple"] }x Headers

Slide 11

Slide 11 text

HTTP/1.1 200 OK content-length: 21 
 content-type: application/json; charset=UTF-8 {x "time": “30m", "price": 15.00 }x POST /pizza HTTP/1.1 host: pizza.app content-length: 50 content-type: application/json; charset=UTF-8 {x "size": "large", "toppings": ["pineapple"] }x Body

Slide 12

Slide 12 text

HTTP/1.1 200 OK content-length: 21 
 content-type: application/json; charset=UTF-8 {x "time": “30m", "price": 15.00 }x POST /pizza HTTP/1.1 host: pizza.app content-length: 50 content-type: application/json; charset=UTF-8 {x "size": "large", "toppings": ["pineapple"] }x

Slide 13

Slide 13 text

$ nc square.com 80 GET /robots.txt HTTP/1.1 host: square.com HTTP/1.1 301 Moved Permanently location: https://square.com/robots.txt date: Thu, 07 Nov 2019 04:05:21 GMT server: envoy content-length: 0
 $

Slide 14

Slide 14 text

HTTP/0.9 HTTP/1.0 HTTP/1.1 HTTP/2 HTTP/3 1991 1996 1997 2015 2019 HTML only headers and status codes persistent connections multiplexing and binary encoding out-of-order packets and IP address changes

Slide 15

Slide 15 text

HTTP in a Hostile World? • Correct • Ready • Secure • New stuff I’m excited about

Slide 16

Slide 16 text

Correct

Slide 17

Slide 17 text

Send Keefer $20 for
 pizza and beer

Slide 18

Slide 18 text

Send Keefer $20 for
 pizza and beer …

Slide 19

Slide 19 text

… SEND KEEFER $20 FOR
 PIZZA AND BEER!

Slide 20

Slide 20 text

SEND KEEFER $20 FOR
 PIZZA AND BEER! Successfully transferred $40 to Keefer

Slide 21

Slide 21 text

Idempotence • Repeating a request won’t repeat the action

Slide 22

Slide 22 text

What Triggers Repeats? • Users double-tapping the send button • Applications retrying • Network code retrying • Gateways retrying

Slide 23

Slide 23 text

Implementing Idempotence: Identify Intention • Generate a universally unique token in the UI:
 d6abe0fcd5d8c51e6c8a9159a873efcc • Write the outbound intention to a persistent queue, like your app’s SQLite database or your cloud queue service (SQS, etc.) • When processing an action, persist the identifier • The easy way: create a UNIQUE INDEX on the token

Slide 24

Slide 24 text

flickr.com/photos/fsse-info/

Slide 25

Slide 25 text

API Contract v. 1 • Client sends a pizza order in JSON • Server sends HTTP 200 and the delivery info in JSON

Slide 26

Slide 26 text

HTTP/1.1 200 OK { "time": "30m", "price": 15.00 } POST /pizza HTTP/1.1 { "size": "large", "toppings": ["pineapple"] }

Slide 27

Slide 27 text

API Contract v. 2 • Client sends a pizza order in JSON • Success: Server sends HTTP 200 and the delivery info in JSON • Failure: Server sends HTTP 500 and the failure info in JSON

Slide 28

Slide 28 text

POST /pizza HTTP/1.1 { "size": "large", "toppings": ["pineapple"] } HTTP/1.1 500 OK { "message": "too many carbs" }

Slide 29

Slide 29 text

Middleboxes!

Slide 30

Slide 30 text

Middleboxes!

Slide 31

Slide 31 text

Designing HTTP APIs • Conceptually, your client talks to your server • In practice, ‘invisible’ infrastructure exists • Sometimes it fails to be invisible

Slide 32

Slide 32 text

Status Codes just a sec thumbs up! response is elsewhere client problem server problem 1xx 2xx 3xx 4xx 5xx

Slide 33

Slide 33 text

Resilient to Middle Boxes • Send Content-Type on outbound requests • Expect Content-Type on inbound responses • HTTP 200? All Good • Other status codes? Be defensive!

Slide 34

Slide 34 text

REST: Retrofit interface PizzaShop { @GET("/{store}/{date}/deliveries") fun deliveries( @Path("store") store: String, @Path("date") date: String ): Call> } square.github.io/retrofit

Slide 35

Slide 35 text

service PizzaShop { rpc OrderFeed (stream Update) returns (stream Order) { } } gRPC: Wire 3 square.github.io/wire

Slide 36

Slide 36 text

interface PizzaShopClient : Service { @WireRpc( path = "/yum.pizza.PizzaShop/OrderFeed", requestAdapter = "yum.pizza.Update#ADAPTER”, responseAdapter = "yum.pizza.Order#ADAPTER" ) fun OrderFeed(): GrpcStreamingCall } gRPC: Wire 3 square.github.io/wire

Slide 37

Slide 37 text

Images: imageView.load("https://pizza.yum/pineapple.png") { crossfade(true) placeholder(R.drawable.image) transformations(CircleCropTransformation()) } Coil coil-kt.github.io/coil

Slide 38

Slide 38 text

Testing: MockWebServer github.com/square/okhttp/mockwebserver val server = MockWebServer() server.start() server.enqueue(MockResponse() .setHeader("Cookie", "fave_topping=pineapple") .setBody("""{"time": "30m", "price": 19.99 }""")) val serverUrl = server.url("/")

Slide 39

Slide 39 text

Debugging: Charles Proxy charlesproxy.com

Slide 40

Slide 40 text

Debugging: Charles Proxy • Observe all your HTTP calls charlesproxy.com

Slide 41

Slide 41 text

Debugging: Charles Proxy • Observe all your HTTP calls • Intercepts HTTPS! charlesproxy.com

Slide 42

Slide 42 text

Ready

Slide 43

Slide 43 text

Redundancy! • Mechanisms to sync across multiple data centers • For availability and operations

Slide 44

Slide 44 text

Connectivity is a Lie • Bell and Rogers fail • Backends fail • Graceful fallbacks are possible

Slide 45

Slide 45 text

Request Avoidance • Push vs. poll • Local models in SQLite, etc.

Slide 46

Slide 46 text

Caching • URLs may represent resources, not calls • Resources can be cached!

Slide 47

Slide 47 text

Cache-Control: no-cache, no-store, max-age=1, s-maxage=2, private, must-revalidate, max-stale=3, min-fresh=4, only-if-cached, no-transform

Slide 48

Slide 48 text

Precise Caching • Just understand all of the above headers • Too difficult!

Slide 49

Slide 49 text

Good-Enough Caching • It may change
 Cache-Control: max-age=0 • It will never change
 Cache-Control: max-age=31536000

Slide 50

Slide 50 text

val cache = Cache( directory = File(context.cacheDir, "http"), maxSize = 100L * 1024 * 1024 ) val client = OkHttpClient.Builder() .cache(cache) .build()

Slide 51

Slide 51 text

Compression • Make sure gzip responses are enabled on client and server • Cuts size by 70% for JSON! • Consider gzip requests too • Use brotli for best compression

Slide 52

Slide 52 text

CDNs • Content Delivery Networks • Easiest way to improve upon speed of light • Great for availability • These can do image resizing!

Slide 53

Slide 53 text

Granularity • HTTP/1’s per-resource overhead is high • More speed?
 Fewer resources! • With HTTP/2 logical resources are best whatsapp.com

Slide 54

Slide 54 text

Secure

Slide 55

Slide 55 text

Data is Dangerous • You’re keeping other people’s secrets • You don’t really know what’s secret and what’s not • Attackers are persistent

Slide 56

Slide 56 text

Other People’s Secrets? • Passwords are obvious • Lots of bigger, less obvious failures

Slide 57

Slide 57 text

Limit Exposure to Data • Are we collecting this field because we need it? • When will we delete it? • GDPR in Europe, CCPA in California • Differential Privacy

Slide 58

Slide 58 text

No content

Slide 59

Slide 59 text

TLS: Necessary • Transport Layer Security is the s in https:// • Confirms that you’re really talking to https://cash.app/ • Prevents eavesdropping • Prevents interference

Slide 60

Slide 60 text

TLS: Not Sufficient • Doesn’t impact how https://cash.app/ secures the data • Doesn’t prevent URLs like https://cash.app.attacker.com/ • Old implementations of TLS had severe bugs • Nation-state attackers do nasty things

Slide 61

Slide 61 text

No content

Slide 62

Slide 62 text

Nation-State Attacks • A certificate authority is a company that confirms ownership of https://cash.app/ and signs our TLS certificate • By default browsers trust ~300 certificate authorities (CAs) • Nation states add themselves to the browser • Or compromise a vulnerable certificate authority

Slide 63

Slide 63 text

No content

Slide 64

Slide 64 text

Defending against
 Nation-State Attacks • Certificate Pinning • Limit which of the 300 certificate authorities you trust

Slide 65

Slide 65 text

CertificatePinner certificatePinner = new CertificatePinner.Builder() .add("pizza.yum", "sha256/9TxoNDzGwoGUV8oDSZI8XpGpwyPz0GY/xAyWRLLjpPc=") .add("pizza.yum", "sha256/36Bv98D5O9bYGYRXnMTZJLQRW8i8fvOiWC/TJ4jOhLw=") .add("pizza.yum", "sha256/++iJU8rCHLXviXyKrJ2yqBWjs/5+LAqWuP04dHVHFb0=") .build(); OkHttpClient okHttpClient = new OkHttpClient.Builder() .certificatePinner(certificatePinner) .build();

Slide 66

Slide 66 text

TLS Evolution first widely-used release renamed from SSL to TLS bug fixes & new crypto bug fixes & new crypto major update with simplifications! 1996 1999 2006 2008 2018 SSLv3 TLSv1 TLSv1.1 TLSv1.2 TLSv1.3

Slide 67

Slide 67 text

TLS Evolution first widely-used release renamed from SSL to TLS bug fixes & new crypto bug fixes & new crypto major update with simplifications! JAN 2020 1996 1999 2006 2008 2018 SSLv3 TLSv1 TLSv1.1 TLSv1.2 TLSv1.3

Slide 68

Slide 68 text

TLS Evolution first widely-used release renamed from SSL to TLS bug fixes & new crypto bug fixes & new crypto major update with simplifications! JAN 2020 1996 1999 2006 2008 2018 Android 5+ Or Google Play Security Provider SSLv3 TLSv1 TLSv1.1 TLSv1.2 TLSv1.3

Slide 69

Slide 69 text

Whitebox Attackers • Our apps are instruction manuals for reverse engineers • There are amazing tools that make this point-and-click easy

Slide 70

Slide 70 text

github.com/sensepost/objection Objection

Slide 71

Slide 71 text

Defending Against
 Whitebox Attackers • A sufficiently-determined attacker will succeed • All we can do is make it really annoying • Perhaps a magic HTTP header?

Slide 72

Slide 72 text

New Stuff I’m Excited About

Slide 73

Slide 73 text

Envoy • Middleboxes are so 2018 • Let’s add side-boxes! envoyproxy.io

Slide 74

Slide 74 text

No content

Slide 75

Slide 75 text

No content

Slide 76

Slide 76 text

HTTP/3 • Better worst-case latency • Change your IP address without restarting downloads! quicwg.org

Slide 77

Slide 77 text

TCP streams Requests and Responses TCP packets HTTP/1.1

Slide 78

Slide 78 text

TCP streams Requests and Responses TCP packets HTTP/1.1 TCP streams TLS streams Requests and Responses TCP packets HTTP/1.1 with TLS

Slide 79

Slide 79 text

TCP streams Requests and Responses TCP packets HTTP/1.1 TCP streams TLS streams Requests and Responses TCP packets HTTP/1.1 with TLS TCP streams TLS streams HTTP/2 frames TCP packets HTTP/2 with TLS Requests and Responses

Slide 80

Slide 80 text

TCP streams Requests and Responses TCP packets HTTP/1.1 TCP streams TLS streams Requests and Responses TCP packets HTTP/1.1 with TLS TCP streams TLS streams HTTP/2 frames TCP packets HTTP/2 with TLS Requests and Responses UDP packets HTTP/3 with TLS Requests and Responses QUIC streams

Slide 81

Slide 81 text

• What if Retrofit inspired a server framework? • gRPC + REST in one framework • Early days! Watch this space cashapp.github.io/misk

Slide 82

Slide 82 text

OkHttp • New concurrency internals • Performance Features • Async I/O and coroutines square.github.io/okhttp

Slide 83

Slide 83 text

@jessewilson Thanks Toronto! https://square.github.io/okhttp/