A presentation at Devoxx Poland 2017 in in Kraków, Poland by Daniel Sawano
@ DanielDeogun @DanielSawano #D evoxxPL Platinum Sponsor: Cracking the Code to Secure Software Daniel Deogun & Daniel Sawano
@ DanielDeogun @DanielSawano #D evoxxPL Daniel Deogun Daniel Sawano
@ DanielDeogun @DanielSawano #D evoxxPL 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.
@ DanielDeogun @DanielSawano #D evoxxPL 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 .”
@ DanielDeogun @DanielSawano #D evoxxPL Key Takeaway By focusing on good design principles you can create secure software without constantly thinking about security.
@ DanielDeogun @DanielSawano #D evoxxPL • Domain Primitives • Entity Snapshots • Dealing with Legacy Code • Security in your Delivery Pipeline • Domain DoS Attacks What we’ll cover today… Design patterns Security & tests Upcoming threat
@ DanielDeogun @DanielSawano #D evoxxPL Domain Primitives A value object so precise in its definition that it, by its mere existence, manifests its validity is called a domain primitive .
@ DanielDeogun @DanielSawano #D evoxxPL • 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 Domain Primitives
@ DanielDeogun @DanielSawano #D evoxxPL 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
@ DanielDeogun @DanielSawano #D evoxxPL • Confidentiality
@ DanielDeogun @DanielSawano #D evoxxPL 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
@ DanielDeogun @DanielSawano #D evoxxPL Domain Primitives External context Your context Email Email Defined by RFC Defined by you
@ DanielDeogun @DanielSawano #D evoxxPL 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 Domain Primitives
@ DanielDeogun @DanielSawano #D evoxxPL ✓ Domain Primitives • Entity Snapshots • Dealing with Legacy Code • Security in your Delivery Pipeline • Domain DoS Attacks What we’ll cover today… Design patterns Security & tests Upcoming threat
@ DanielDeogun @DanielSawano #D evoxxPL • 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 Entities
@ DanielDeogun @DanielSawano #D evoxxPL 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); }
// ... }
@ DanielDeogun @DanielSawano #D evoxxPL 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 Entity Snapshots
@ DanielDeogun @DanielSawano #D evoxxPL 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; } // ... }
@ DanielDeogun @DanielSawano #D evoxxPL 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 } }
@ DanielDeogun @DanielSawano #D evoxxPL ✓ Domain Primitives ✓ Entity Snapshots • Dealing with Legacy Code • Security in your Delivery Pipeline • Domain DoS Attacks What we’ll cover today… Design patterns Security & tests Upcoming threat
@ DanielDeogun @DanielSawano #D evoxxPL Dealing with Legacy Code [6] Declutter Entities Harden your APIs Draw the Line [7] [8] 3 good design patterns
@ DanielDeogun @DanielSawano #D evoxxPL • We need to identify the semantic boundary of a context • Add a layer that internally translates data to a domain primitive and then 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 Draw the Line [6]
@ DanielDeogun @DanielSawano #D evoxxPL • Create a library of domain primitives • Express your APIs with your domain primitives • Never accept generic input if you have specific requirements Harden the API Generic Specific [7] void buyBook(ISBN, Quantity) void buyBook(String, int)
@ DanielDeogun @DanielSawano #D evoxxPL 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)); } } }
@ DanielDeogun @DanielSawano #D evoxxPL 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)); } }
@ DanielDeogun @DanielSawano #D evoxxPL ✓ Domain Primitives ✓ Entity Snapshots ✓ Dealing with Legacy Code • Security in your Delivery Pipeline • Domain DoS Attacks What we’ll cover today… Design patterns Security & tests Upcoming threat
@ DanielDeogun @DanielSawano #D evoxxPL Security in your Delivery Pipeline [10] [12]
@ DanielDeogun @DanielSawano #D evoxxPL The Hospital Case [9]
@ DanielDeogun @DanielSawano #D evoxxPL Email Domain Primitive External context Your context Email Email Defined by RFC Defined by you
@ DanielDeogun @DanielSawano #D evoxxPL Normal & Boundary Testing Normal Boundary Tests with i nput that clearly meets the domain rules Tests that verify behavior around the boundary
@ DanielDeogun @DanielSawano #D evoxxPL Email Address v1.0 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(); } ... }
@
DanielDeogun @DanielSawano
#D
evoxxPL
Invalid Input Testing
•
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
@
DanielDeogun @DanielSawano
#D
evoxxPL
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)));
}
@ DanielDeogun @DanielSawano #D evoxxPL Email Address v2.0 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(); } ... }
@
DanielDeogun @DanielSawano
#D
evoxxPL
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())));
}
@ DanielDeogun @DanielSawano #D evoxxPL Inefficient Backtracking v.s "^ (?=[a-z0-9.@]{15,77}$) [a-z0-9]+\.?[a-z0-9]+@\bhospital.com$" “^ [a-z0-9]+\.?[a-z0-9]+@\bhospital.com$"
@ DanielDeogun @DanielSawano #D evoxxPL ✓ Domain Primitives ✓ Entity Snapshots ✓ Dealing with Legacy Code ✓ Security in your Delivery Pipeline • Domain DoS Attacks What we’ll cover today… Design patterns Security & tests Upcoming threat
@ DanielDeogun @DanielSawano #D evoxxPL • The main objective of a DoS attack is to prevent availability of a system’s services • A DoS attack doesn’t require heavy load to be successful (asymmetric) DoS Attacks
@ DanielDeogun @DanielSawano #D evoxxPL Domain DoS Attacks A DoS attack caused by utilizing domain rules in a malicious way is called a Domain DoS
@ DanielDeogun @DanielSawano #D evoxxPL We need great customer service! Domain DoS Example - The Hotel Full refund if cancelled before 4 p.m. Book all empty rooms No rooms available for ordinary customers [9]
@ DanielDeogun @DanielSawano #D evoxxPL Uber vs Ola [4]
@ DanielDeogun @DanielSawano #D evoxxPL Lyft vs Uber [5]
@ DanielDeogun @DanielSawano #D evoxxPL Key Takeaway By focusing on good design principles you can create secure software without constantly thinking about security.
@ DanielDeogun @DanielSawano #D evoxxPL Questions & More [2] URL: http://bit.ly/secure-by-design Discount code: ctwdevoxxpl17 (40% off) Want a free ebook? Catch us in the break!
@ DanielDeogun @DanielSawano #D evoxxPL [1] https://www.flickr.com/photos/stewart/461099066 by Stewart Butterfield under license https://creativecommons.org/licenses/by/2.0/ [2] https://flic.kr/p/9ksxQa by Damián Navas under license https://creativecommons.org/licenses/by-nc-nd/2.0/ [3] https://flic.kr/p/nEZKMd by Graeme Fowler under license https://creativecommons.org/licenses/by/2.0/ [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] 3d key, https://flic.kr/p/e9qfrf by Yoel Ben-Avraham under license https://creativecommons.org/licenses/by-nd/2.0/ [7] Building blocks, https://flic.kr/p/agPw7C by Tiffany Terry under license https://creativecommons.org/licenses/by/2.0/ [8] Doctors Stock Photo, https://flic.kr/p/HNJUzV, by Sergio Santos under license https://creativecommons.org/licenses/by/2.0/ [9] “Anonymous” - Icon made by Egor Rumyantsev from www.flaticon.com - CC 3.0 References
What is it that makes writing secure software so difficult? Why do we keep making the same mistakes over and over again? One challenge is that developers are busy delivering features and meeting deadlines – giving security requirements less priority.
In this talk you’ll learn to use principles and mindsets from Domain Driven Design combined with a pinch of security awareness, to create secure code – while still focusing on your business features.
You’ll learn the basic principles of Secure by Design and how to use concepts such as Domain Primitives and Entity Snapshots to harden your code. What a Domain DoS attack is, and how to incorporate security testing in your delivery pipeline. The ideas and tools presented are directly applicable in your daily work.
The following resources were mentioned during the presentation or are useful additional information.