Secure by Design

A presentation at DevDays Vilnius 2017 in May 2017 in Vilnius, Lithuania by Daniel Sawano

Slide 1

Slide 1

@DanielDeogun @DanielSawano DevDays 2017, Vilnius Secure by Design Daniel & Daniel 
 @DanielDeogun @DanielSawano DevDays, Vilnius 2017

Slide 2

Slide 2

@DanielDeogun @DanielSawano DevDays 2017, Vilnius Daniel Deogun Daniel Sawano About us…

Slide 3

Slide 3

@DanielDeogun @DanielSawano DevDays 2017, Vilnius Secure by Design Secure by Design is a new approach to software security that lets you create secure software while still focusing on business features.

Slide 4

Slide 4

@DanielDeogun @DanielSawano DevDays 2017, Vilnius Secure by Design “Any activity involving active decision making

should be considered part of the software design process and can thus be referred to as design .”

  • Johnsson, Deogun, and Sawano

Slide 5

Slide 5

@DanielDeogun @DanielSawano DevDays 2017, Vilnius What we’ll cover today… • Domain Primitives • Entity Snapshots • Dealing with Legacy Code • Security in your Pipelines Design Patterns Security & tests

Slide 6

Slide 6

@DanielDeogun @DanielSawano DevDays 2017, Vilnius Domain Primitives A value object so precise in its definition that it, by its mere existence, manifests its validity is called a domain primitive .

Slide 7

Slide 7

@DanielDeogun @DanielSawano DevDays 2017, Vilnius Domain Primitives • A Domain Primitive is very strict in its definition

• If it’s not valid then it cannot exist • Defined in the current domain

• It’s preciseness brings robustness in your code

• It’s immutable so it will always be valid

Slide 8

Slide 8

@DanielDeogun @DanielSawano DevDays 2017, Vilnius Domain Primitives import static org.apache.commons.lang3.Validate.inclusiveBetween; import static org.apache.commons.lang3.Validate.notNull; public final class Quantity { private final int value; public Quantity(final int value) { inclusiveBetween(1, 200, value); this.value = value;

} public int value() { return value;

} public Quantity add(final Quantity addend) { notNull(addend); return new Quantity(value + addend.value); } // ... } Quantity is not just an int! • Enforces invariants at creation • Provides domain operations to • Encapsulate domain behavior

Slide 9

Slide 9

@DanielDeogun @DanielSawano DevDays 2017, Vilnius CIA • Confidentiality

  • protecting data from being read by unauthorized users

• Integrity

  • ensures data is changed in an authorized way

• Availability

  • concerns having data available when authorized users need it [11]

Slide 10

Slide 10

@DanielDeogun @DanielSawano DevDays 2017, Vilnius Domain Primitives import static org.apache.commons.lang3.Validate.inclusiveBetween; import static org.apache.commons.lang3.Validate.notNull; public final class Quantity { private final int value; public Quantity(final int value) { inclusiveBetween(1, 200, value); this.value = value;

} public int value() { return value;

} public Quantity add(final Quantity addend) { notNull(addend); return new Quantity(value + addend.value); } // ... } Quantity is not just an int! • Enforces invariants at creation • Provides domain operations to • Encapsulate domain behavior

Slide 11

Slide 11

@DanielDeogun @DanielSawano DevDays 2017, Vilnius Domain Primitives External context Your context Email Email Defined by RFC Defined by you

Slide 12

Slide 12

@DanielDeogun @DanielSawano DevDays 2017, Vilnius Domain Primitives Use Domain Primitives as: • the smallest building block in your domain model • to build your Domain Primitive Library • to harden your code and your APIs

Slide 13

Slide 13

@DanielDeogun @DanielSawano DevDays 2017, Vilnius What we’ll cover today… ✓ Domain Primitives • Entity Snapshots • Dealing with Legacy Code • Security in your Pipelines Design Patterns Security & tests

Slide 14

Slide 14

@DanielDeogun @DanielSawano DevDays 2017, Vilnius Entities • An entity has an identity that doesn’t change over time • The values/data belonging to an entity can change over time • Typically modeled as mutable objects

Slide 15

Slide 15

@DanielDeogun @DanielSawano DevDays 2017, Vilnius Classic Entity public final class Order { private final OrderId id; private final List<OrderItem> orderItems = new ArrayList<>(); public Order(final OrderId id) { this.id = notNull(id); } public void addItem(final OrderItem item) { notNull(item); orderItems.add(item); }

// ... }

Slide 16

Slide 16

@DanielDeogun @DanielSawano DevDays 2017, Vilnius Perils of mutable state • Mutability is a source of security issues • Consistency in the presence of contention is hard • Contention can reduce availability

Slide 17

Slide 17

@DanielDeogun @DanielSawano DevDays 2017, Vilnius Entity Snapshots Entity Snapshots are: • Securing mutable state by making it immutable • An immutable representation of a mutable entity • Solves many of the security problems with regular entities

Slide 18

Slide 18

@DanielDeogun @DanielSawano DevDays 2017, Vilnius Entity Snapshots public final class Order { private final OrderId id; private final List<OrderItem> orderItems; public Order(final OrderId id, final List<OrderItem> orderItems) { noNullElements(orderItems); notNull(id); this.id = id; this.orderItems = unmodifiableList(new ArrayList<>(orderItems)); } public List<OrderItem> orderItems() { return orderItems; } // ... }

Slide 19

Slide 19

@DanielDeogun @DanielSawano DevDays 2017, Vilnius Entity Snapshots public final class WritableOrder { private final OrderId id; private final OrderRepository repository; public WritableOrder(final OrderId id, final OrderRepository repository) { this.id = notNull(id); this.repository = notNull(repository); } public void addOrderItem(final OrderItem orderItem) { notNull(orderItem); isOkToAdd(orderItem); repository.addItemToOrder(id, orderItem); } private void isOkToAdd(final OrderItem orderItem) { // domain validation logic to ensure it's ok to add order } }

Slide 20

Slide 20

@DanielDeogun @DanielSawano DevDays 2017, Vilnius What we’ll cover today… ✓ Domain Primitives ✓ Entity Snapshots • Dealing with Legacy Code • Security in your Pipelines Design Patterns Security & tests

Slide 21

Slide 21

@DanielDeogun @DanielSawano DevDays 2017, Vilnius Dealing with Legacy Code 3 good design patterns [6] Declutter Entities Harden your APIs Draw the Line [7] [8]

Slide 22

Slide 22

@DanielDeogun @DanielSawano DevDays 2017, Vilnius “Draw the Line” [6] • We need to identify the semantic boundary of a context • Add a layer that internally translates data to a domain primitive and the back again

data -> domain primitive -> data • This way, we have created a validation boundary that protects the inside from bad input • But, if rejecting data is to harsh, consider logging it for insight

Slide 23

Slide 23

@DanielDeogun @DanielSawano DevDays 2017, Vilnius “Harden the API” • Create a library of domain primitives • Express your APIs with your domain primitives • Never accept generic input if you have specific requirements Generic Specific [7] void buyBook(ISBN, Quantity) void buyBook(String, int)

Slide 24

Slide 24

@DanielDeogun @DanielSawano DevDays 2017, Vilnius “Decluttering Entities” [8] import static org.apache.commons.lang3.Validate.notNull; import static org.apache.commons.lang3.Validate.isTrue; public class Order { 
 
 private final List<Object> items; 
 private boolean paid; 
 
 public void addItem(String isbn, int qty) { 
 if (this.paid == false) { 
 notNull(isbn); 
 isTrue(isbn.length() == 10); 
 isTrue(isbn.matches("[0-9X]*")); 
 isTrue(isbn.matches(“[0-9]{9}[0-9X]”)); if (inventory.avaliableBooks(isbn, qty)) {

Book book = bookcatalogue.findBy(isbn); 
 items.add(new OrderLine(book, qty)); 
 } 
 } 
 }

Slide 25

Slide 25

@DanielDeogun @DanielSawano DevDays 2017, Vilnius “Decluttering Entities” [8] import static org.apache.commons.lang3.Validate.notNull; import static org.apache.commons.lang3.Validate.isTrue; public class Order { 
 
 private final List<Object> items; 
 private boolean paid; 
 
 public void addItem(final ISBN isbn, final Quantity quantity) { notNull(isbn); notNull(quantity); isTrue(notPaid());

    if (inventory.avaliableBooks(isbn, quantity)) {
        

Book book = bookcatalogue.findBy(isbn); 
 items.add(new OrderLine(book, quantity)); 
 } 
 }

Slide 26

Slide 26

@DanielDeogun @DanielSawano DevDays 2017, Vilnius What we’ll cover today… ✓ Domain Primitives ✓ Entity Snapshots ✓ Dealing with Legacy Code • Security in your Pipelines Design Patterns Security & tests

Slide 27

Slide 27

@DanielDeogun @DanielSawano DevDays 2017, Vilnius Security in your Pipelines [10] [12]

  • Unit testing

Slide 28

Slide 28

@DanielDeogun @DanielSawano DevDays 2017, Vilnius The Hospital Case [9]

Slide 29

Slide 29

@DanielDeogun @DanielSawano DevDays 2017, Vilnius Email Domain Primitive External context Your context Email Email Defined by RFC Defined by you

Slide 30

Slide 30

@DanielDeogun @DanielSawano DevDays 2017, Vilnius The Domain Rules • The format of an email address must be local-part@domain

• The local part cannot be longer than 64 characters

• The domain must be hospital.com

• Subdomains are not accepted • The minimum length of an email address is 15 characters

• The maximum length of an email address is 77 characters

• The local part may only contain alphabetic characters (a-z), digits (0-9), and one period • The local part may not start or end by a period [5]

Slide 31

Slide 31

@DanielDeogun @DanielSawano DevDays 2017, Vilnius Testing Normal Behavior • F ocus on input that clearly meets the domain rules class EmailAddressTest { @TestFactory Stream<DynamicTest> should_be_a_valid_address() { return Stream.of(
"jane@hospital.com",
"jane01@hospital.com",
"jane.doe@hospital.com")
.map(input -> dynamicTest("Accepted: " + input,
() -> new EmailAddress(input)));
} }

Slide 32

Slide 32

@DanielDeogun @DanielSawano DevDays 2017, Vilnius 1 st version of EmailAddress public final class EmailAddress { public final String value; public EmailAddress(final String value) {

matchesPattern (value.toLowerCase(),
"^[a-z0-9]+\.?[a-z0-9]+@\bhospital.com$"); this.value = value.toLowerCase();
} ... }

Slide 33

Slide 33

@DanielDeogun @DanielSawano DevDays 2017, Vilnius Testing Boundary B ehavior

  • Acceptance • Accept an address that's exactly 15 characters long. • Accept an address with a local part that's 64 characters long. • Accept an address that's exactly 77 characters long.

@TestFactory Stream<DynamicTest> should_be_accepted() { return Stream.of( "aa@hospital.com",
repeat("X", 64) + "@hospital.com")
.map(input -> dynamicTest("Accepted: " + input, () -> new EmailAddress(input))); } Email

Slide 34

Slide 34

@DanielDeogun @DanielSawano DevDays 2017, Vilnius Testing Boundary B ehavior

Rejection • Reject an address that's 14 characters long • Reject an address with a local part that's 65 characters long • Reject an address with a local part containing an invalid character • Reject an address with multiple '@' symbols • Reject an address with a domain other than hospital.com

• Reject an address with a subdomain • Reject an address with a local part that starts with a period • Reject an address with a local part that ends with a period • Reject an address with sequential periods in the local part

Slide 35

Slide 35

@DanielDeogun @DanielSawano DevDays 2017, Vilnius Testing Boundary B ehavior

Rejection

@TestFactory Stream<DynamicTest> should_be_rejected() { return Stream.of( "a@hospital.com",
repeat("X", 65) + "@hospital.com",
"address_with_invalid_char_in_local_part@hospital.com", "jane@doe@hospital.com",
"jane.doe@hospital.lt ",
"jane.doe@hospital.io",
"jane.doe@hospital.gov",
"jane.doe@example.com",
"jane.doe@cardio .hospital.com",
".jane.doe@hospital.com",
"jane.doe.@hospital.com",
"jane..doe@hospital.com")
.map(input -> dynamicTest("Rejected: " + input, assertInvalidEmail(input))); }

Slide 36

Slide 36

@DanielDeogun @DanielSawano DevDays 2017, Vilnius 2 nd version of EmailAddress public final class EmailAddress { public final String value; public EmailAddress(final String value) {

matchesPattern (value.toLowerCase(), "^ (?=[a-z0-9.@]{15,77}$) [a-z0-9]+\.?[a-z0-9]+@\bhospital.com$"); this.value = value.toLowerCase(); } ... }

Slide 37

Slide 37

@DanielDeogun @DanielSawano DevDays 2017, Vilnius Testing with Invalid Input

• Any input that doesn't satisfy the domain rules is considered invalid

• For some reason, null, empty strings, or "strange" characters tend to result in unexpected behavior Email

Slide 38

Slide 38

@DanielDeogun @DanielSawano DevDays 2017, Vilnius Testing with Invalid Input

@TestFactory Stream<DynamicTest> should_reject_invalid_input() { return Stream.of( null,
"null",
"nil",
"0",
"",
" ",
" ",
" ",
"john.doe @hospital.com",
" @hospital.com",
"%20@hospital.com",
"john.d%20e@hospital.com",
"john.doe.jane@hospital.com",
"--",
"e x a m p l e @ hospital . c o m",
"=0@$*^%;<!->.:\()&#"") .map(input -> dynamicTest("Rejected: " + input,

assertInvalidEmail(input))); }

Slide 39

Slide 39

@DanielDeogun @DanielSawano DevDays 2017, Vilnius 3 rd version of EmailAddress public final class EmailAddress { public final String value; public EmailAddress(final String value) {

notNull (value, "Input cannot be null");

matchesPattern (value.toLowerCase(), "^(?=[a-z0-9.@]{15,77}$)[a-z0-9]+\.?[a-z0-9]+@\bhospital.com$"); this.value = value.toLowerCase(); } ... }

Slide 40

Slide 40

@DanielDeogun @DanielSawano DevDays 2017, Vilnius Testing with Extreme Input • Testing the extreme is all about identifying weaknesses in the design that makes the application break or behave strangely when handling extreme values. @TestFactory Stream<DynamicTest> should_reject_extreme_input() { return Stream.<Supplier<String>>of( () -> repeat("x ", 10000),
() -> repeat("x ", 100000),
() -> repeat("x ", 1000000),
() -> repeat("x ", 10000000), () -> repeat("x ", 20000000),
() -> repeat("x ", 40000000)) .map(input -> dynamicTest("Rejecting extreme input", assertInvalidEmail(input.get()))); }

Slide 41

Slide 41

@DanielDeogun @DanielSawano DevDays 2017, Vilnius Security weaknesses caused by
inefficient backtracking v.s "^[a-z0-9]+\.?[a-z0-9]+@\bhospital.com$" "^ (?=[a-z0-9.@]{15,77}$) [a-z0-9]+\.?[a-z0-9]+@\bhospital.com$"

Slide 42

Slide 42

@DanielDeogun @DanielSawano DevDays 2017, Vilnius What we have covered… ✓ Domain Primitives ✓ Entity Snapshots ✓ Dealing with Legacy Code ✓ Security in your Pipelines Design Patterns Security & tests

Slide 43

Slide 43

@DanielDeogun @DanielSawano DevDays 2017, Vilnius URL http s://manning.com Discount code:

ctwdevdays Part 1: Introduction

  1. Why Design Matters for Security
  2. Case-Study: An Anti-Hamlet for sale Part 2: Fundamentals
  3. Core concepts of Domain Driven Design
  4. Code Constructs Promoting Security
  5. Securing mutable state
  6. Leveraging your delivery pipeline for security
  7. Handling failures in a secure way
  8. Case-study: Insurance policy for free
  9. Integrating system of systems with security in mind
  10. Benefits from cloud thinking Part 3: Applying the Fundamentals
  11. Getting a fresh start in a legacy codebase
  12. The subtle issues in a pretty monolith
  13. Getting microservices right for security
  14. A final word: don’t forget about security [1]

Slide 44

Slide 44

@DanielDeogun @DanielSawano DevDays 2017, Vilnius Q&A [2]

Slide 45

Slide 45

@DanielDeogun @DanielSawano DevDays 2017, Vilnius Thank you! 
 @DanielSawano @DanielDeogun

Slide 46

Slide 46

@DanielDeogun @DanielSawano DevDays 2017, Vilnius References [1] Book cover, Secure by Design, Manning Publication [2] Question mark, https://flic.kr/p/9ksxQa by Damián Navas under license https://creativecommons.org/licenses/by-nc-nd/2.0/

[3] DDos Attack, Secure by Design, Manning Publication
[4] Uber vs Ola, https://www.bloomberg.com/news/articles/2016-03-23/uber-sues-ola-claiming-fake-bookings-as-india-fight-escalates

[5] Lyft vs Uber, http://time.com/3102548/lyft-uber-cancelling-rides/

[6] Boundary, https://flic.kr/p/nEZKMd by Graeme Fowler under license https://creativecommons.org/licenses/by/2.0/

[7] 3d key, https://flic.kr/p/e9qfrf by Yoel Ben-Avraham under license https://creativecommons.org/licenses/by-nd/2.0/

[8] Building blocks, https://flic.kr/p/agPw7C by Tiffany Terry under license https://creativecommons.org/licenses/by/2.0/

[9] Doctors Stock Photo, https://flic.kr/p/HNJUzV , by Sergio Santos under license https://creativecommons.org/licenses/by/2.0/

[10] Anonymous, https://flic.kr/p/a2eniw, by Lio Leiser under license https://creativecommons.org/licenses/by-nd/2.0/

[11] CIA, https://goo.gl/images/DRzRcp

[12] Bilfinger - Natural gas pipeline USA, https://flic.kr/p/nrFHFz by Bilfinger SE under license https://creativecommons.org/licenses/by-nd/2.0/