Secure by Design
Dan Bergh Johnsson, Daniel Deogun, Daniel Sawano
  • MEAP began January 2017
  • Publication in Spring 2019 (estimated)
  • ISBN 9781617294358
  • 375 pages (estimated)
  • printed in black & white

It's a pretty fantastic book, which shows how to build security in by focusing on robustness, thereby getting a lot of security along for the ride.

Christoffer Fink

As a developer, you need to build software in a secure way. But you can't spend all your time focusing on security. The answer is to use good design principles, tools, and mindsets that make security an implicit result - it's secure by design. Then secure-by-design becomes a guiding principle in how you build your software, from code to architecture. This begins by understanding designs and patterns that promote security so they become easy to apply in your day-to-day work. This way, you end up with securely-built software that avoids a majority of the most common security vulnerabilities. And best of all, it liberates your mind from security and lets you focus on developing features.

Secure by Design teaches developers how to use design to drive security in software development. This book is full of patterns, best practices, and mindsets that you can directly apply to your real world development. You'll also learn to spot weaknesses in legacy code and how to address them. You'll start by gaining an understanding of security as a vital concern and not simply a feature, and how good design promotes security. A real-life case study shows how shallow design caused a severe loss of money. Then you'll dive into practical ways of designing your code to avoid security flaws. You'll see how to use concrete code constructs that have profound effect on security - for example, immutability, validation, domain primitives, and error handling. Additional topics include how to secure your design through tests, using your delivery pipeline, how to do integration between systems, and how insights from cloud thinking support security. The final part of the book compares different architectures from a security perspective and puts concepts from previous chapters to work. In particular, you'll learn what to do in a legacy codebase, how to handle a monolith, and what to do when building a microservice architecture.

Table of Contents detailed table of contents

Part 1: Introduction

1. Why design matters for security

1.1. Security is a concern, not a feature

1.1.1. The robbery of #214;st-Götha Bank 1854

1.1.2. Security features and security concerns

1.2. Defining design

1.2.1. What is design?

1.3. The traditional approach to software security

1.3.1. The shortcomings of the traditional approach

1.4. Driving security through design

1.4.1. Making the User secure by design

1.4.2. The advantages of the design approach

1.4.3. Staying eclectic

1.5. Dealing with strings, XML, and a billion laughs

1.5.1. Internal XML entities in a nutshell

1.5.2. The Billion Laughs attack

1.5.3. Configuring the XML parser

1.5.4. Applying a design mindset

1.5.5. Achieving security in depth

1.6. Summary

2. Intermission: The Anti-Hamlet

2.1. Online book store with business integrity issues

2.1.1. The inner workings of the accounts receivable ledger

2.1.2. How the inventory system tracks books in the store

2.1.3. Shipping of anti-books

2.1.4. Systems living the same lie

2.1.5. A do-it-yourself discount voucher

2.2. Shallow modeling

2.2.1. How shallow models emerge

2.2.2. Implicit concepts, and the dangers thereof

2.3. Deep modeling

2.3.1. How deep models emerge

2.3.2. Make the implicit explicit

2.4. Summary

Part 2: Fundamentals

3. Core concepts of Domain-Driven Design

3.1. Models as a tool for deeper insight

3.1.1. Models are simplifications

3.1.2. Models are strict

3.1.3. Models capture deep understanding

3.1.4. Making a model means choosing one

3.1.5. The model forms the ubiquitous language

3.2. Building blocks for your model

3.2.1. Entities

3.2.2. Value objects

3.2.3. Aggregates

3.3. Bounded contexts

3.3.1. Semantics of the ubiquitous language

3.3.2. The relationship between language, model, and bounded context

3.3.3. Identifying the bounded context

3.4. Interactions between contexts

3.4.1. Sharing a model in two contexts

3.4.2. Drawing a context map

3.5. Summary

4. Code constructs promoting security

4.1. Immutability

4.1.1. An ordinary webshop

4.2. Validation

4.2.1. Checking origin of data

4.2.2. Checking size of data

4.2.3. Checking lexical content of data

4.2.4. Checking syntax of data

4.2.5. Checking semantics of data

4.3. Domain primitives and invariants

4.3.1. Domain primitives as the smallest building blocks

4.3.2. Context boundaries define meaning

4.3.3. Building your domain primitive library

4.3.4. Hardening your APIs by using your domain primitive library

4.4. Read-once objects

4.4.1. Detecting unintentional use

4.4.2. Avoiding leaks caused by evolving code

4.5. Summary

5. Domain primitives

5.1. Domain primitives and invariants

5.1.1. Domain primitives as the smallest building blocks

5.1.2. Context boundaries define meaning

5.1.3. Building your domain primitive library

5.1.4. Hardening your APIs by using your domain primitive library

5.1.5. Avoid exposing your domain publicly

5.2. Read-once objects

5.2.1. Detecting unintentional use

5.2.2. Avoiding leaks caused by evolving code

5.3. Standing on the shoulders of domain primitives

5.3.1. The risk with overcluttered entity methods

5.3.2. Decluttering entities

5.3.3. When to use domain primitives in entities

5.4. Taint analysis

5.5. Summary

6. Ensuring integrity of state

6.1. Managing state using entities

6.2. Consistent upon creation

6.2.1. The perils of no-arg constructors

6.2.2. ORM frameworks and no-arg constructors

6.2.3. All mandatory fields as constructor arguments

6.2.4. Construction with a fluent interface

6.2.5. Catching advanced constraints in code

6.2.6. The builder pattern for upholding advanced constraints

6.2.7. ORM frameworks and advanced constraints

6.2.8. Which construction to use when

6.3. Integrity of entities

6.3.1. Set/get methods

6.3.2. Avoid sharing mutable objects

6.3.3. Securing integrity of collections

6.4. Summary

7. Reducing complexity of state

7.1. Partially immutable entities

7.2. Entity state objects

7.2.1. Upholding entity state rules

7.2.2. Implementing entity state as a separate object

7.3. Entity snapshots

7.3.1. Entities represented with immutable objects

7.3.2. Changing the state of the underlying entity

7.3.3. When to use snapshots

7.4. Entity relay

7.4.1. Splitting the state graph into phases

7.4.2. When to form an entity relay

7.5. Summary

8. Leveraging your delivery pipeline for security

8.1. Using a delivery pipeline

8.2. Securing your design using unit tests

8.2.1. Understanding the domain rules

8.2.2. Testing normal behavior

8.2.3. Testing boundary behavior

8.2.4. Testing with invalid input

8.2.5. Testing the extreme

8.3. Verifying feature toggles

8.3.1. The perils of slippery toggles

8.3.2. Feature toggling as a development tool

8.3.3. Taming the toggles

8.3.4. Dealing with combinatory complexity

8.3.5. Toggles are subject to auditing

8.4. Automated security tests

8.4.1. Security tests are just tests

8.4.2. Working with security tests

8.4.3. Leveraging infrastructure as code

8.4.4. Putting it into practice

8.5. Testing for availability

8.5.1. Estimating the headroom

8.5.2. Exploiting domain rules

8.6. Validating configuration

8.6.2. Automated tests as your safety net

8.6.3. Know your defaults and verify them

8.7. Summary

9. Handling failures securely

9.1. Using exceptions to deal with failure

9.1.1. Throwing exceptions

9.1.2. Handling exceptions

9.1.3. Dealing with exception payload

9.2. Handling failures without exceptions

9.2.1. Failures are not exceptional

9.2.2. Designing for failures

9.3. Designing for availability

9.3.1. Resilience

9.3.2. Responsiveness

9.3.3. Circuit breakers and timeouts

9.3.4. Bulkheads

9.4. Handling bad data

9.4.1. Don’t repair data before validation

9.4.2. Never echo input verbatim

9.5. Summary

10. Benefits of cloud thinking

10.1. The twelve-factor app and cloud native concepts

10.2. Storing configuration in the environment

10.2.1. Don’t put configuration in code

10.2.2. Never store secrets in resource files

10.2.3. Placing configuration in the environment

10.3. Separate processes

10.3.1. Security benefits

10.4. Avoid logging to file

10.4.1. Confidentiality

10.4.2. Integrity

10.4.3. Availability

10.4.4. Logging as a service

10.5. Admin processes

10.5.1. The security risk of overlooked admin tasks

10.5.2. Admin tasks as first-class citizens

10.6. Service discovery and load balancing

10.6.1. Centralized load balancing

10.6.2. Client-side load balancing

10.6.3. Embrace change

10.7. The three R’s of enterprise security

10.7.1. Increase change to reduce risk

10.7.2. Rotate

10.7.3. Repave

10.7.4. Repair

10.8. Summary

11. Intermission: An insurance policy for free

11.1. Over-the-counter insurance policies

11.2. Separating services

11.3. A new payment type

11.4. A crashed car, a late payment, and a court case

11.5. Understanding what went wrong

11.6. Seeing the entire picture

11.7. A note on microservices architecture

11.8. Summary

Part 3: Applying the Fundamentals

12. Guidance in legacy code

12.1. Determining where to apply domain primitives in legacy code

12.1.1. Identifying a semantic boundary

12.2. Ambiguous parameter lists

12.2.1. The direct approach

12.2.2. The discovery approach

12.2.3. The new API approach

12.3. Logging unchecked strings

12.3.1. Identifying logging of unchecked strings

12.3.2. Identifying implicit data leakage

12.4. Defensive code constructs

12.4.1. Code that doesn’t trust itself

12.4.2. Contracts and domain primitives to the rescue

12.4.3. Overlenient use of Optional

12.5. DRY misapplied—​not focusing on ideas, but on text

12.5.1. A false positive that should not be DRY’d away

12.5.2. The problem of collecting repeated pieces of code

12.5.3. The good DRY

12.5.4. A false negative

12.6. Insufficient validation in domain types

12.7. Only testing the "good enough"

12.8. Partial domain primitives

12.8.1. Implicit, contextual currency

12.8.2. A US dollar is not a Slovenian tolar

12.8.3. Encompassing a conceptual whole

12.9. Summary

13. Guidance on microservices

13.1. What is a microservice?

13.1.1. Independent runtimes

13.1.2. Independent updates

13.1.3. Designed for down

13.2. Each service is a bounded context

13.2.1. The importance of designing your API

13.2.2. Splitting monoliths

13.2.3. Semantics and evolving services

13.3. Sensitive data across services

13.3.1. CIA-T in a microservice architecture

13.3.2. Thinking "sensitive"

13.4. Logging in microservices

13.4.1. Integrity of aggregated log data

13.4.2. Traceability in log data

13.4.3. Confidentiality through a domain-oriented logger API

13.5. Summary

14. A final word, don’t forget about security

What's inside

  • Using good design to create secure software
  • Applying design concepts in real-world cases
  • Spotting hidden security problems
  • Assessing security by identifying design patterns
  • Understanding benefits and limitations of secure‐by‐design
  • Securing legacy, monoliths, and microservice architectures

About the reader

Readers should have some experience in Java, C#/.NET, or similar language.

About the authors

Dan Bergh Johnsson, Daniel Deogun, and Daniel Sawano have collectively been working with security and development for several decades. They are developers at heart and understand that security is often a side-concern. They have also evolved work habits that enable them to develop systems in a way that promotes security, while focusing on high-quality design habits - something that is easier for developers to keep in mind during their daily work. All three are established international speakers and often present at conferences on topics regarding high-quality development as well as security.

Manning Early Access Program (MEAP) Read chapters as they are written, get the finished eBook as soon as it’s ready, and receive the pBook long before it's in bookstores.

FREE domestic shipping on three or more pBooks

Excellent book. Every developer should read it.

David Raymond

An exceptional book that once again shows how software is not created by using fancy tools and technologies but by thinking hard about your problem.

Daut Morina