jdd2014: what you won't read in books about implementing rest services - jakub kubryński

48
The thin line between RESTful and AWful Jakub Kubrynski [email protected] / @jkubrynski 1 / 48

Upload: proidea

Post on 01-Jul-2015

126 views

Category:

Software


2 download

DESCRIPTION

REST is as plain as the nose on your face. However, often exploring the secrets of this pattern ends up with the positive completion of two "Hello, World" class challenges. During this lecture we will focus on common problems and ways of handling them. We will deal with the security and best practices on topics like HATEOAS or versioning.

TRANSCRIPT

Page 1: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

The thin line between RESTful and AWfulJakub Kubrynski

[email protected] / @jkubrynski 1 / 48

Page 2: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

[email protected] / @jkubrynski 2 / 48

Page 3: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

"The Code is more what you'd call guidelines than actual rules. Welcomeaboard the Black Pearl, Miss Turner"

-- Cpt. Hector Barbossa to Elizabeth Swann

RT Ben Hale

[email protected] / @jkubrynski 3 / 48

Page 4: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

Formal REST constraintsClient-Server

Stateless

Cache

Interface / Uniform Contract

Layered System

[email protected] / @jkubrynski 4 / 48

Page 5: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

Richardson maturity model

http://martinfowler.com/articles/richardsonMaturityModel.html

[email protected] / @jkubrynski 5 / 48

Page 6: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

POST vs PUT

[email protected] / @jkubrynski 6 / 48

Page 7: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

POST vs PUTPOST creates new resources

[email protected] / @jkubrynski 7 / 48

Page 8: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

POST vs PUTPOST creates new resources

PUT updates existing resources

PUT can create resource if ID is already known

[email protected] / @jkubrynski 8 / 48

Page 9: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

Maybe PATCH?no "out of the box" support

[email protected] / @jkubrynski 9 / 48

Page 10: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

Maybe PATCH?no "out of the box" support

partial update

@RequestMapping(value = "/{id}", method = PATCH)public void updateArticle(HttpServletRequest request, @PathVariable("id") String id) { Article currentArticle = repository.findOne(id);

Article updatedArticle = objectMapper.readerForUpdating(currentArticle) .readValue(request.getReader());

repository.save(updatedArticle);}

[email protected] / @jkubrynski 10 / 48

Page 11: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

Cachingbe aware - especially IE caches aggressively

[email protected] / @jkubrynski 11 / 48

Page 12: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

Cachingbe aware - especially IE caches aggressively

disable caching

@Configurationpublic class RestConfig extends WebMvcConfigurerAdapter {

@Override public void addInterceptors(InterceptorRegistry registry) { WebContentInterceptor webContentInterceptor = new WebContentInterceptor(); webContentInterceptor.setCacheSeconds(0); registry.addInterceptor(webContentInterceptor); }}

[email protected] / @jkubrynski 12 / 48

Page 13: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

Cache headerscache-control: public, max-age=0, no-cache

public / privateno-cacheno-storemax-ages-maxage

[email protected] / @jkubrynski 13 / 48

Page 14: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

Cache headerscache-control: public, max-age=0, no-cache

public / privateno-cacheno-storemax-ages-maxage

ETag

If-None-Match: "0d41d8cd98f00b204e9800998ecf8427e"Spring brings ShallowEtagHeaderFilter

[email protected] / @jkubrynski 14 / 48

Page 15: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

Compressionreduces response size dramatically

in Tomcat extend Connector with

compression="on"compressionMinSize="2048"noCompressionUserAgents="gozilla, traviata"compressableMimeType="text/html,text/xml"

[email protected] / @jkubrynski 15 / 48

Page 16: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

HATEOASself-descriptive

client understands hypermedia

{ "name": "Alice", "links": [ { "rel": "self", "href": "/customers/1213" }, { "rel": "parent", "href": "/customers/14" }, { "rel": "currentOrder", "href": "/orders/14312" } ]}

HTTP/1.1 201 CreatedLocation: http://api.mydomain.com/orders/1234

[email protected] / @jkubrynski 16 / 48

Page 17: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

HATEOAS in Springpublic class Customer extends ResourceSupport { ... }// or wrap entity into Resource object

[email protected] / @jkubrynski 17 / 48

Page 18: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

HATEOAS in Springpublic class Customer extends ResourceSupport { ... }// or wrap entity into Resource object

import static org.springframework.hateoas.mvc.ControllerLinkBuilder.*;

public HttpEntity<Customer> get(@PathVariable("id") String customerId) { Customer customer = repository.findOne(customerId); String pId = customer.getBoss(); String oId = customer.currentOrderId();

customer.add(linkTo(methodOn(CustomerController.class).get(customerId)).withSelfRel()); customer.add(linkTo(methodOn(CustomerController.class).get(pId)).withRel("parent")); customer.add(linkTo(methodOn(OrderController.class).get(oId)).withRel("currentOrder"));

return new ResponseEntity<Customer>(customer, HttpStatus.OK);}

public ResponseEntity create(@RequestBody Customer customer) { String id = repository.save(customer); return ResponseEntity.created(linkTo(CustomerController.class).slash(id).toUri()) .build();}

[email protected] / @jkubrynski 18 / 48

Page 19: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

@DanaDanger HTTP codes classification20x: cool

30x: ask that dude over there

40x: you fucked up

50x: we fucked up

[email protected] / @jkubrynski 19 / 48

Page 20: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

Exceptionsinclude detailed information

{ "status": 400, "code": 40483, "message": "Incorrect body signature", "moreInfo": "http://www.mycompany.com/errors/40483"}

[email protected] / @jkubrynski 20 / 48

Page 21: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

Exceptionsinclude detailed information

{ "status": 400, "code": 40483, "message": "Incorrect body signature", "moreInfo": "http://www.mycompany.com/errors/40483"}

hide stacktrace

[email protected] / @jkubrynski 21 / 48

Page 22: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

Handling Spring MVC exceptions@ControllerAdvicepublic class MyExceptionHandler extends ResponseEntityExceptionHandler {

/* Handling framework exceptions */ @Override protected ResponseEntity<Object> handleExceptionInternal(Exception ex, Object body, HttpHeaders headers, HttpStatus status, WebRequest request) { LOG.error("Spring MVC exception occurred", ex); return super.handleExceptionInternal(ex, body, headers, status, request); }

/* Handling application exceptions */ @ResponseStatus(value = HttpStatus.NOT_FOUND) @ExceptionHandler(ResourceNotFoundException.class) public void handleResourceNotFound() { }}

[email protected] / @jkubrynski 22 / 48

Page 23: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

API Versioningdon't even think aboutapi.domain.com/v2/orders

URIs to the same resources should be fixed betweenversions

[email protected] / @jkubrynski 23 / 48

Page 24: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

API Versioningdon't even think aboutapi.domain.com/v2/orders

URIs to the same resources should be fixed betweenversions

use Content-Type

1 version: application/vnd.domain+json

2 version: application/vnd.domain.v2+json

[email protected] / @jkubrynski 24 / 48

Page 25: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

Filtering and sortingGET /reviews?rating=5

GET /reviews?rating=5&sortAsc=author

[email protected] / @jkubrynski 25 / 48

Page 26: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

Filtering and sortingGET /reviews?rating=5

GET /reviews?rating=5&sortAsc=author

Dynamic queries are easier in POST body

[email protected] / @jkubrynski 26 / 48

Page 27: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

Filtering and sortingGET /reviews?rating=5

GET /reviews?rating=5&sortAsc=author

Dynamic queries are easier in POST body

POST /reviews/searches

GET /reviews/searches/23?page=2

[email protected] / @jkubrynski 27 / 48

Page 28: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

Documentationrunnable with examples

Swagger

[email protected] / @jkubrynski 28 / 48

Page 29: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

[email protected] / @jkubrynski 29 / 48

Page 30: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

Stateless or not?password hashing cost

session replication

load-balancing

[email protected] / @jkubrynski 30 / 48

Page 31: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

Stateless or not?password hashing cost

session replication

load-balancing

...

stateless session?

[email protected] / @jkubrynski 31 / 48

Page 32: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

Avoiding session creation in Spring@EnableWebSecuritypublic class SpringSecurity extends WebSecurityConfigurerAdapter {

@Override protected void configure(HttpSecurity http) throws Exception { http .csrf().disable() .authorizeRequests() .antMatchers("/secure/**").fullyAuthenticated() .and()

.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER)

.and() .httpBasic(); }}

[email protected] / @jkubrynski 32 / 48

Page 33: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

SecuritySQL Injection

XSS

CSRF

XXE

[email protected] / @jkubrynski 33 / 48

Page 34: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

HQL InjectionList<Product> products = em.createQuery( "SELECT p FROM Product p where p.category = '" + categ + "'", Product.class) .getResultList();

[email protected] / @jkubrynski 34 / 48

Page 35: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

HQL InjectionList<Product> products = em.createQuery( "SELECT p FROM Product p where p.category = '" + categ + "'", Product.class) .getResultList();

categ = ' OR '1'='1

[email protected] / @jkubrynski 35 / 48

Page 36: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

HQL InjectionList<Product> products = em.createQuery( "SELECT p FROM Product p where p.category = '" + categ + "'", Product.class) .getResultList();

categ = ' OR '1'='1

SELECT __fields__ FROM products WHERE category = '' OR '1'='1'

[email protected] / @jkubrynski 36 / 48

Page 37: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

HQL InjectionList<Product> products = em.createQuery( "SELECT p FROM Product p where p.category = '" + categ + "'", Product.class) .getResultList();

categ = ' OR '1'='1

SELECT __fields__ FROM products WHERE category = '' OR '1'='1'

List<Product> products = em.createQuery( "SELECT p FROM Product p where p.category = :categ", Product.class) .setParameter("categ", categ) .getResultList();

[email protected] / @jkubrynski 37 / 48

Page 38: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

HQL InjectionList<Product> products = em.createQuery( "SELECT p FROM Product p where p.category = '" + categ + "'", Product.class) .getResultList();

categ = ' OR '1'='1

SELECT __fields__ FROM products WHERE category = '' OR '1'='1'

List<Product> products = em.createQuery( "SELECT p FROM Product p where p.category = :categ", Product.class) .setParameter("categ", categ) .getResultList();

SELECT __fields__ FROM products WHERE category = ' OR ''1''=''1'''

[email protected] / @jkubrynski 38 / 48

Page 39: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

CSRF - Cross-site request forgery<img src="https://api.mybank.com/transfers/from/1233/to/1234/amount/5000">

<form action="https://api.mybank.com/transfers" method="POST"> <input type="hidden" name="from" value="1233"/> <input type="hidden" name="to" value="1234"/> <input type="hidden" name=amount" value="5000"/> <input type="submit" value="Celebrity Nude Photos!"/></form>

[email protected] / @jkubrynski 39 / 48

Page 40: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

CSRF - Cross-site request forgery<img src="https://api.mybank.com/transfers/from/1233/to/1234/amount/5000">

<form action="https://api.mybank.com/transfers" method="POST"> <input type="hidden" name="from" value="1233"/> <input type="hidden" name="to" value="1234"/> <input type="hidden" name=amount" value="5000"/> <input type="submit" value="Celebrity Nude Photos!"/></form>

One time request tokens

Correct CORS headers

[email protected] / @jkubrynski 40 / 48

Page 41: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

CORS - Cross Origin Requests SharingPreflight request

OPTIONS /cors HTTP/1.1Origin: http://www.domain.comAccess-Control-Request-Method: PUTAccess-Control-Request-Headers: X-Custom-HeaderHost: api.mydomain.orgAccept-Language: en-USConnection: keep-aliveUser-Agent: Mozilla/5.0...

Preflight response

Access-Control-Allow-Origin: http://www.domain.comAccess-Control-Allow-Methods: GET, POST, PUTAccess-Control-Allow-Headers: X-Custom-HeaderContent-Type: text/html; charset=utf-8

[email protected] / @jkubrynski 41 / 48

Page 42: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

XML External Entity<?xml version="1.0" encoding="utf-8"?><comment> <text>Yeah! I like it!</text></comment>

[email protected] / @jkubrynski 42 / 48

Page 43: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

XML External Entity<?xml version="1.0" encoding="utf-8"?><comment> <text>Yeah! I like it!</text></comment>

<?xml version="1.0" encoding="utf-8"?><!DOCTYPE myentity [ <!ENTITY a "Yeah! I like it!"> ]><comment> <text>&a;</text></comment>

[email protected] / @jkubrynski 43 / 48

Page 44: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

XML External Entity<?xml version="1.0" encoding="utf-8"?><!DOCTYPE myentity [ <!ENTITY a SYSTEM "/etc/passwd"> ]><comment> <text>&a;</text></comment>

[email protected] / @jkubrynski 44 / 48

Page 45: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

XML External Entity<?xml version="1.0" encoding="utf-8"?><!DOCTYPE myentity [ <!ENTITY a SYSTEM "/etc/passwd"> ]><comment> <text>&a;</text></comment>

<?xml version="1.0" encoding="utf-8"?><comment> <text>root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown halt:x:7:0:halt:/sbin:/sbin/halt ..... </text></comment>

[email protected] / @jkubrynski 45 / 48

Page 46: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

XML External Entity<?xml version="1.0" encoding="utf-8"?><!DOCTYPE myentity [<!ENTITY a "abcdefghij1234567890" > <!ENTITY b "&a;&a;&a;&a;&a;&a;&a;&a;&a;&a" > <!ENTITY c "&b;&b;&b;&b;&b;&b;&b;&b;&b;&b;" > <!ENTITY d "&c;&c;&c;&c;&c;&c;&c;&c;&c;&c;" > ...<!ENTITY h "&g;&g;&g;&g;&g;&g;&g;&g;&g;&g;" >]><comment> <text>&h;</text></comment>

[email protected] / @jkubrynski 46 / 48

Page 47: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

http://knowyourmeme.com/photos/531557 thx to @mihn

[email protected] / @jkubrynski 47 / 48

Page 48: JDD2014:  What you won't read in books about implementing REST services - Jakub Kubryński

Thanks!

[email protected] / @jkubrynski 48 / 48