Building Blocks

Since it’s something I’m really passionate about, I have decided to spend more time writing about application security at scale.

Today I’m going to cover one of the things that can help an application security team save a lot of time: Building Blocks.

In many organisations, multiple development teams will often need to perform the same thing (especially with µ-services):

  • Authentication layer
  • Authorisation
  • Rendering
  • Sending information in a queue
  • Save files in s3/GCP/…

The problem is that every team is likely to come up with their own solution using their own languages/framework/… and the cost for the security team (and the development teams) increases with each solution. The application security team find itself reviewing the same type of code again and again. Often, the same mistakes are made and the same recommendations always follow:

  • More input filtering.
  • Better block mode for encryption.
  • Better default value.

The trend of Resume-Driven Development making this even worst.

To avoid repeating the same reviews (which can be pretty boring too), an application security team can work with other teams (dev, ops, devops,compliance…) to build “Building Blocks” that can be reused by everyone.

These “Building Blocks” will be thoroughly reviewed by the security team and consider “secure”. They can then be provided as libraries to all the development teams.

Creating these blocks will help teams scale up as and the security team won’t have to review the same code again and again. It will also lower the consulting effort (read: meetings), as you won’t have to provide each team with Best Practice for X, you can just tell them to use the “Building Block X” that already include all the best practices, has been reviewed and is supported by all the other teams (including the ops team that on call).

Building the blocks

The blocks don’t have to be complex, they also don’t have to (shouldn’t) be created by the security team. They can just be open source components reviewed by the security team and packaged in a secure way (think smart default). The security can also finance the development of these blocks: the security team uses its budget to pay for the development of a block (or part of it).

To make things easier, the building blocks should be versioned. This will allow all teams to quickly know what applications are using old blocks.

Promoting

One of the ways to promote the building blocks is first to not build them in isolation. You need to get everyone involved: architects, developers, QA teams, Ops. To ensure a broad adoption, these blocks should benefit every team:

  • They should follow the architects’ visions.
  • They should be easy to develop with (and elegant) for developers.
  • They should be easy to test for the QA team.
  • They should be easy to debug for Ops.

The security team should also communicate why these blocks are so valuable for them: it is their way of scaling. If other teams don’t want to use the blocks, they should have a good reason and they should understand that the security review of their software will take more time and may not be prioritised.

Examples of blocks

Blocks don’t have to be complex and don’t have to be big. You can find below some examples of blocks:

  • Encryption at Rest
  • Encryption with an HSM
  • Using Queues (encryption of information transmitted, TLS for connection to the queue)
  • Database access

You can also see these “Building Blocks” as a way to make sure the security team is involved in everything that will shape the future of development in the organisation:

  • New micro-service patterns
  • New language or framework adoption
  • New technology (MQ, GraphQL, Serverless) or pattern.
Adding a layer to the blocks

A final thing that could be beneficial is to add another layer to a block to make sure the interface stays constant even if the library underneath changes. This thin layer can also be used for additional/unified logging as well as error-proofing the block.

Deep dive in a block

Let’s say we want to create an authentication block for our default µ-service template. The financing of the block can be split between development teams (creating the template) and the security team (smart default, error proofing…). We want this block to use JWT (sic.).

The first version of the block can just be a packaging of the most commonly used library (by the organisation) used for JWT in the language picked. The first version gets reviewed by the security team and can be used by everyone. This version only allows developers to use the secure functions/methods available for this library (think verify() vs decode()).

The second version adds to the thin layer on top of the JWT library. For example, it will enforce the strength of the secret used to sign the token (to avoid offline brute force attacks) and enforce the algorithm (to avoid confusion attack). It also adds some extra-logging that goes directly to the security team: for example when a signature is invalid.

Since the security and ops teams pushed really hard to deploy Vault by HashiCorp, all the secrets are now centralised in Vault and decrypted at runtime by the library. All of this without creating any changes for the development teams. The versioning is also allowing the security and ops team to know who is not using Vault yet

Conclusion

I hope this quick blog post convince you of the importance of using blocks if you want to scale the impact of your security team. Finally, building these blocks will also help to create relationships between teams. These relationships are often critical to solve complex problems and during incidents. Thanks for reading!

Photo of Louis Nyffenegger
Written by Louis Nyffenegger
Founder and CEO @PentesterLab