Application Security

How it Works: TOTP Based MFA

Aaron Bedra No Comments

Introduction

Multi-Factor Authentication has become a requirement for any application that values security. In fact, it has become a regulatory requirement in some industries and is being adopted as a requirement in several others. We often discover misconceptions or downright misunderstandings about how MFA works and think this is a topic worth diving into. This particular article will focus on one of the most common second factors, Time based One Time Password, or TOTP.

TOTP authentication uses a combination of a secret and the current time to derive a predictable multi-digit value. The secret is shared between the issuer and the user in order to compare generated values to determine if the user in fact posses the required secret. You may have heard this incorrectly referred to as “Google Authenticator”. While Google had a major part in popularizing this method, it has nothing to do with how TOTP actually works. Any site may create and issue tokens and any mobile application with a correct implementation of TOTP generation may produce a one time value. In this article we will implement server side TOTP token issuing and discuss its security requirements.

To read more about TOTP token generation, please take a look at RFC 6238.

The example code in this article is written in Java. This task can be accomplished in any programming language that supports the underlying cryptographic functions.

Establishing a Seed

The foundation for the security of a TOTP token begins with the seed. This value is used in conjunction with the current time to derive the instance of the token. Because time can be calculated it is not suitable as the only value for our token. Choosing a seed is incredibly important and should not be left up to the user. Seeds should be randomly generated using a Cryptographically Secure Pseudo Random Number Generator. You can determine the number of bytes you want to use, and in this example we are using 64. We will use the SecureRandom implementation provided by the Java language.

static String generateSeed() {
    SecureRandom random = new SecureRandom();
    byte[] randomBytes = new byte[SEED_LENGTH_IN_BYTES];
    random.nextBytes(randomBytes);
    return printHexBinary(randomBytes);
}

In order to cosume the token we will return the hex representation of the bytes generated. This allows us to pass the value around a bit easier.

Establishing a counter

The other side of TOTP token generation relies on the current time. We take the current time represented as a long, which is the number of seconds since epoch. This can be derived using System.currentTimeMillis() / 1000L. Next, we take the value and divide it by our period, or the number of seconds the token will be valid before rotating. We will use a value of 30 in our example, which is the recommended setting. Finally, we need to put the value into a byte array. There are a few ways to do this, but the following method is on the conservative side accounting for non 64 bit longs and possible endian differences.

private static byte[] counterToBytes(long time) {
    long counter = time / PERIOD;
    byte[]
    buffer = new byte[Long.SIZE / Byte.SIZE];
    for (int i = 7; i >= 0; i--) {
        buffer[i] = (byte)(counter & 0xff);
        counter = counter >> 8;
    }
    return buffer;
}

Once we have this value we can execute our hmac operation to produce the long form of our OTP value.

Generating a Value

Using the seed as a key and the counter as a message, we will derive our long form OTP value. The value returned from our HMac operation will be truncated in order to produce the 6 digit value we will compare against in the end. The following code is an HMacSHA1 operation using the standard Java encryption libraries. While RFC 6238 describes the possible options of HMacSHA256 and HMacSHA512, they are not viable when distributing the secret for use on most mobile authenticator applications.

private static byte[] hash(final byte[] key, final byte[] message) {
    try {
        Mac hmac = Mac.getInstance("HmacSHA1");
        SecretKeySpec keySpec = new SecretKeySpec(key, "RAW");
        hmac.init(keySpec);
        return hmac.doFinal(message);
    } catch (NoSuchAlgorithmException | InvalidKeyException e) {
        log.error(e.getMessage(), e);
        return null;
    }
}

With the ability to hash our seed and message we can now derive our TOTP value:

static String generateInstance(final String seed, final byte[] counter) {
    byte[] key = hexToBytes(seed);
    byte[] result = hash(key, counter);

    if (result == null) {
        throw new RuntimeException("Could not produce OTP value");
    }

    int offset = result[result.length - 1] & 0xf;
    int binary = ((result[offset]     & 0x7f) << 24) |
                 ((result[offset + 1] & 0xff) << 16) |
                 ((result[offset + 2] & 0xff) << 8)  |
                 ((result[offset + 3] & 0xff));

    StringBuilder code = new StringBuilder(Integer.toString(binary % POWER));
    while (code.length() < DIGITS) code.insert(0, "0"); 
    return code.toString(); 
}

Using the seed as the key and the counter as the message, we perform the necessary conversions, perform the hash, and truncate the message according to the specification. Finally, we divide the result by 10 to the power of the expected digits (in our case 6) and convert that to a string value. If the result is less than 6 digits we pad it with zeros.

Providing the Secret to the User

In order to provide the secret to the user, we need to provide a consistent string in a format that allows the user to generate tokens reliably. There are several ways to do this, including simply providing the secret and issuer to the user directly. The most common method is by providing a QR code that contains the information. For this example we will use the Zebra Crossing library.

class QrCode {
    private static final int WIDTH = 350;
    private static final int HEIGHT = 350;

    static void generate(String applicationName, String issuer, String path, String secret) {
        try {
            String qrdata = String.format("otpauth://totp/%s?secret=%s&issuer=%s", applicationName, secret, issuer);
            generateQRCodeImage(qrdata, path);
        } catch (WriterException | IOException e) {
            System.out.println("Could not generate QR Code: " + e.getMessage());
        }
    }

    private static void generateQRCodeImage(String text, String filePath) throws WriterException, IOException {
        QRCodeWriter qrCodeWriter = new QRCodeWriter();
        BitMatrix bitMatrix = qrCodeWriter.encode(text, BarcodeFormat.QR_CODE, WIDTH, HEIGHT);
        Path path = FileSystems.getDefault().getPath(filePath);
        MatrixToImageWriter.writeToPath(bitMatrix, "PNG", path);
    }
}

Executing this code will save a PNG with the corresponding QR code. In a real world situation, you would render this image directly to the user for import by their application of choice.

Consuming the Token

In order to test our implementation we will need a program that can accept an otpauth:// string or a QR Code. This can be done a number of ways. If you want to do this via a mobile device, you can use Google Authenticator or Authy. Both of these programs will scan a QR code. If you want to try locally, 1Password provides a way to import a QR image by adding a label to a login and selecting One-Time Password as the type. You can import the created image using the QR code icon and selecting the path to the generated image. Once the secret is imported it will start producing values. You can use these as your entry values into the example program.

Protecting the Seed

It is important to respect the secret for what it is — a secret. With any secret we must do our part to protect it from misuse. How do we do this? Like any other piece of persisted sensitive information, we encrypt it. Because these secrets are not large in size, we have a number of options at our disposal. The important part is not to manage this step on your own. Take advantage of a system that can encrypt and decrypt for you and just worry about storing the encrypted secret value. There are cloud based tools like Amazon KMS, Google Cloud Key Management, and Azure Key Vault as well as services you can run like Thycotic Secret Server, CyberArk Conjur, and Hashicorp Vault. All of these options require some kind of setup, and some are commercial products.

Setting up Secret Storage

To keep this example both relevant and free of cost to run, we will use Hashicorp Vault. Vault is an open source project with an optional enterprise offering. It’s a wonderful project with capabilities far past this example. There are a number of ways to install Vault, but since it is a single binary, the easiest way is to download the binary and run it. Start vault with the development flag:

λ vault server -dev

During the boot sequence you will be presented with an unseal key and a root token. The example program will expect the VAULT_TOKEN environment variable to be set to the root token provided. Your output will be similar to the following:

λ vault server -dev ==> Vault server configuration:

Api Address: http://127.0.0.1:8200
Cgo: disabled
Cluster Address: https://127.0.0.1:8201
Listener 1: tcp (addr: "127.0.0.1:8200", cluster address: "127.0.0.1:8201", max_request_duration: "1m30s", max_request_size: "33554432", tls: "disabled")
Log Level: (not set)
Mlock: supported: false, enabled: false
Storage: inmem
Version: Vault v0.11.2
Version Sha: 2b1a4304374712953ff606c6a925bbe90a4e85dd

WARNING! dev mode is enabled! In this mode, Vault runs entirely in-memory
and starts unsealed with a single unseal key. The root token is already
authenticated to the CLI, so you can immediately begin using Vault.

You may need to set the following environment variable:

$ set VAULT_ADDR=http://127.0.0.1:8200

The unseal key and root token are displayed below in case you want to
seal/unseal the Vault or re-authenticate.

Unseal Key: mkniY94IlJngQz07gfPZlQnZnvEHMXWQ3/MiFegsfr8=
Root Token: 4uYnD1vVZZcNkbYe03t0cLkh

Development mode should NOT be used in production installations!

Once Vault is booted you will need to enable the Transit Backend. This allows us to create an encryption key inside of Vault and seamlessly encrypt and decrypt information.

λ export VAULT_ADDR=http://127.0.0.1:8200
λ vault secrets enable transit
Success! Enabled the transit secrets engine at: transit/

λ vault write -f transit/keys/how_it_works_totp
Success! Data written to: transit/keys/how_it_works_totp

λ echo "my secret" | base64
Im15IHNlY3JldCIgDQo=

λ vault write transit/encrypt/myapp plaintext=Im15IHNlY3JldCIgDQo=
Key Value
--- -----
ciphertext vault:v1:/HeILzBTv+JbxdaYeKLVB9RVH9o/b+Lilrja88VhCuaSSlvUY+IzHp2Uλ vault write transit/encrypt/myapp plaintext=Im15IHNlY3JldCIgDQo=

λ vault write -field=plaintext transit/decrypt/myapp ciphertext=vault:v1:/HeILzBTv+JbxdaYeKLVB9RVH9o/b+Lilrja88VhCuaSSlvUY+IzHp2U | base64 -d
"my secret"

We can now encrypt and decrypt our TOTP secrets. The only thing left is to persist those secrets so that they can be referenced on login. For this example we will not be creating a complete user system, but we will setup a database and create an entry with an encrypted seed value to show what the end to end process will resemble.

To encrypt and decrypt our seed we can use a Vault library. The following example demonstrates the essential pieces:

String encryptSeed(String seed) throws VaultException {
    final Map<String, Object> entry = new HashMap<>();
    entry.put("plaintext", seed);
    final LogicalResponse response = client.logical().write("transit/encrypt/myapp", entry);
    return response.getData().get("ciphertext");
}

String decryptSeed(String ciphertext) throws VaultException {
    final Map<String, Object> entry = new HashMap<>();
    entry.put("ciphertext", ciphertext);
    final LogicalResponse response = client.logical().write("transit/decrypt/myapp", entry);
    return response.getData().get("plaintext");
}

Note the lack of error handling. In a production system you would want to handle the negative and null cases appropriately.

Finally, we take the output of the vault encryption operation and store it in our database. The sample code contains database handling logic, but it is typical boilerplate database code an not directly relevant to explaining the design of a TOTP system.

Drift

By now it should be pretty obvious that time synchronization is of the utmost importance. If the server and client differ more than the period, the token comparison will fail. The RFC describes methods for determining drift and tolerance for devices that have drifted for too many periods. This example does not address drift or resynchronization, but it is recommended that a production implementation address this issue.

Running the Example

The source code for this example is available on Github. Make sure you have read an executed all of the steps above before attempting to run the example. Additionally, you will need to have PostgreSQL installed and running. If this is your first time running the example, you will need to be sure to import the generated token using your preferred application before attempting to type in a value. You should have your MFA token generator application open and the test token selected. You can setup and execute the program by running:

createdb totp
mvn flyway:migrate
mvn compile
# For Unix users
export VAULT_TOKEN=XXX
# For Windows users
set VAULT_TOKEN=XXX
mvn -q exec:java -Dexec.mainClass=com.jemurai.howitworks.totp.Main

You will be prompted to enter your token value. After pressing return the program will echo the value you entered, the expected token value, and if the values match. This is the core logic necessary to confirm a TOTP based MFA authentication sequence. If your token values do not match, make sure to enter your token value with plenty of time to spare on the countdown. Because we have not implemented a solution that accounts for drift, the value must be entered during the same period the server generates the expected value. If this is your first time running the example you will need to import the QR code that was generated before the input prompt. If everything was done correctly you will see output similar to the following:

MFA Token:
808973
Entered: 808973 : Generated: 808973 : Match: true

At this point you have successfully implemented server side TOTP based MFA and used a client side token generator to validate the implementation.

Security Pitfalls of TOTP

For a long time TOTP or really, just OTP based MFA was the best option. It was popularized by RSA long before smart phones were capable of generating tokens. This method is fundamentally secure but is open to human error. Well crafted phishing attacks can obtain and replay TOTP based MFA responses. Several years ago FIDO and U2F were introduced and this is now the “most secure” option available. It comes with benefits and drawbacks and like all solutions should be carefully considered before use.

Conclusions

Multi-Factor Authentication is an important part of the security of your information systems. Any system providing access to sensitive information should employ the use of MFA to protect that information. With credential theft via phishing on the rise, this could be one of the most important controls you establish. While this article examines an implementation of TOTP token based MFA, you should seek an established provider like Okta, OneLogin, Duo, Auth0, etc. to provide a production ready solution.

Technology and Security: AI, Cloud, IoT

Matt Konda No Comments

So … someone asked me the following question, so I figured I’d put my answer in a blog post.

In what ways are evolving technology like cloud, AI, IoT affecting the cybersecurity landscape? What kind of cybersecurity threats and risks can they bring to the enterprise?

As technology moves forward, it has huge implications on security.

We talk about AI but what that really is behind the scenes is vast amounts of data.  The security implications of the data are significant.  We are already training AI to create sentencing systems that are unfair based on the training data.  The training data reflect our biases, and then in fact, reinforce them.  AI isn’t just in the background either, it is helping to land planes, drive cars, identify faces in video, identify security events and a million other things.  Also, many great AI systems now have gaps in explainability – meaning we don’t even know how they know what they are telling us.

As a user of AI, I would be very concerned about the integrity of the training data.  Many people believe that we can subvert AI / ML algorithms by feeding them malicious data.  Of course, those same systems are still often processing data that comes from users, so as we look at software, we have the problem of separating control from data.  The scope and nature of the data sets (often photos, video, etc.) pose new challenges as well.  In many cases, security is an afterthought, with access to the data bolted on for users but not proactively designed in.

In terms of the cloud, many things in the cloud give us significant improvements in security.  It is easy to pay a little more to have an HSM, a WAF, encrypted data, a key management system, centralized log management, etc.  That does, however, force us into the major clouds (AWS, Azure, GCP) where these items are offered.  Note that the complexity of the cloud is a major concern.  We recommend that our clients use the “infrastructure as code” model, and use tools like Terraform or CloudFormation to provision systems.  That will allow them to audit, track (and often roll back) changes as needed.

Many organizations embraced cloud as a way to reduce friction, which is another way of saying bending the rules.  Without oversight, teams may be creating large environments that don’t follow proper security practices.  We routinely find services exposed to the internet that companies weren’t aware of.  We see poor password management policies, unencrypted data and lots more.  For CIO’s, a big takeaway is to actively manage the cloud.  We actually build a product related to cloud security https://jasp.cloud.

A great mini case study is AWS Macie.  It reads S3 buckets and categorizes data, then alerts the data owner about what types of data there is and where it moves.  Seems pretty awesome and powerful.  But if I can read the index, now I know a lot about what data you have and I know it much faster than I did before.

IoT is even more of a problem.  Often IoT applies to devices that are hard to manage and weren’t built to be updated.  So we see lots of potential vulnerabilities in the IoT landscape.  There is also an explosion in the number of devices and a they are connected in much less structured ways – often via relatively open home internet.  IoT also comes with custom operating systems, which are often unpatched and ill suited for long term security.

As a takeaway, as more information is distributed to more places, of course this brings escalating privacy concerns.  Our position on this is generally to have clear classification schemes that can be applied to data in a consistent way across these different scenarios.  And then to use AI in the cloud to find the data.  (wink wink)

Reference:

https://www.newscientist.com/article/2166207-discriminating-algorithms-5-times-ai-showed-prejudice/

 

Facebook Access Tokens Were An AppSec Issue That Tools Won’t Catch

Matt Konda No Comments

Yesterday I was doing training for a team of architects, project managers and developers at a client and I realized that a deeper discussion of the issue at Facebook might be instructive.

In looking at the issue in more detail, I came to understand that it makes a perfect learning example for why application security training and team communication around security is so important.

In particular I want to look at:

  • What were the issues?
  • How should they have been prevented?
  • How tools could not have helped to identify these issues.

Disclaimer

Before I go through this though, let me stop and say this:  Facebook may have a great program.  They are likely just as vulnerable as anyone else.  This is not a critique of their process or response.  I am not aware of any of the back story or processes used (or not used) in this case.  The goal of this post is to talk about the learning points we can take away.

The Gory Details

Part 1:  Facebook describes the first problem as an error related to the View As function.  Essentially, the View As feature allows a user to see what a post will look like to another user.  In that view, a link to upload a video was inadvertently included in the preview.

A full discussion of this issue with a villain hat might have revealed that the View As page should not still have an upload link.  This doesn’t feel like a big deal, but it is a classic example of developers and product owners and stakeholders not communicating adequately about requirements or security requirements.  I would guess a pen test would gloss right over this because even the security expert might not be able to assert that the link shouldn’t be there.

Part 2:  The application then generated an access token that was used during that process.  The access token was scoped to the mobile application.   This seems again like an obvious potential issue.  Someone could have or should have asked, is the scope for this access token correct?  This probably is a security question.

Part 3:  The access token was scoped to the wrong user, the “View As” user.  This again is an issue that if I said it out loud, even a product manager could have told us that it was wrong.  So this looks like an example where just having the conversation or making security visible would have substantially helped to eliminate the security issue.

Tools and How To Find The Issue

As a point of note:  none of these items could be found by static analysis, dynamic analysis, RASP/IAST, etc.

Ways to find this issue include:

  • Code Review
  • Security Requirements
  • Security Unit Tests

From my perspective, a take away is that we should be peer reviewing any code that includes access tokens.  It also suggests that training would be helpful.

References: 

Security Update

Facebook Login Update

Validating Search Engine Indexers

Aaron Bedra No Comments

Introduction

Not all bots are created equal. Some bots are good, some bots are bad, and some bots are not what they appear to be. This article will discuss an aspect of bots that attempt to exploit the sensitive nature of SEO optimization rules.

Fundamentals

We love search engines. If it weren’t for search engines most of our sites would never be discovered. When the search engine bot comes knocking, we best let it in, or we will suffer the consequences of not existing. Let’s face it, if you aren’t on the first page of the search results, you don’t exist. Let’s break down a request made by a search engine bot:

66.249.64.147 – – [24/Sep/2018:07:58:32 -0400] “GET / HTTP/1.1” 200 2947 “-” “Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.96 Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)”

We can identify this request as coming from Google’s indexing bot. We do this by examining the User Agent provided during the request. Unfortunately, this header can be set to any value and cannot be trusted. While we understand this, it is common for site operators to always allow this user agent for fear of vanishing from the Internet.

We are now presented with a problem. How do we know that the actor identifying as the Google indexer actually belongs to Google? Luckily the popular search engines typically provide documentation on how to validate an actor. For example, Google documents this process at https://support.google.com/webmasters/answer/80553?hl=en. At this point you are probably wondering how this pattern applies to other search engine bots. The good news is that while the User Agents and valid domains may change, the process is still the same. It goes something like this:

  • Does the User Agent match a list of provided user agent strings?
  • If yes, perform a reverse lookup on the IP address of the actor
  • Examine the domain of the lookup and ensure it matches the provided domain(s)
  • If yes, perform a forward lookup of the host and check to see if the forward lookup matches the IP address provided

If all of these checks pass, the actor is a valid search engine bot. If any of these checks fails, it isn’t. We are now faced with the problem of validating any actor that claims to be a search engine indexer. Blindly allowing these actors introduces a technical weakness that could lead to a loss event. It is interesting to observe this trend in action. You can do so by searching your logs for actors that match a pattern and performing the verification steps manually. You will likely fine a number of actors that fail the test. We have observed that even on low traffic sites, there are requests every day that fail validation.

We all know that doing this manually doesn’t scale and that neither does manual IP blocking. As usual, this is a process that can be automated.

NGINX Bot Verifier

It’s important to keep edge processing at the edge. This is a common mistake in application security. It’s typically easiest to take all application logic and put it in the application. This makes deployment and operations easier. The problem with this practice is that it allows requests to make it to your application that never should have. This presents an opportunity for an actor to exploit a vulnerability in your application. It’s effectively lack of input validation on a meta level. In general, if the request doesn’t look right and your application shouldn’t process it, it should be rejected before your application has to try.

Applying this idea leads us to an obvious choice; do it at the webserver layer. There are options for this, but NGINX is the most widely used webserver available. It also has a nice API for creating custom modules and request handlers. Because this validation process only looks at the User Agent and IP address of the request, it requires very little work to perform the validation and keep actors from hitting our application.

I took some time recently to put this idea into an NGINX module. You can find the code at https://github.com/abedra/ngx_bot_verifier. It’s an open source project and all ideas, pull requests, and issues are welcome. The module handles the validation steps described and works for the following search engines:

  • Google
  • Yahoo!
  • Bing
  • Baidu
  • Yandex

Because the validation happens inline with the request, and the validation requires a response from DNS, that validation can introduce perceived latency. In order to minimize this the module is backed by a Redis cache. All validation results are cached to prevent latency for subsequent requests. The cache expiry is handled by a timeout configured in the module directives and simply expires over a period of time since the last validation.

Why Does it Matter?

You’ve got a lot to do. The point of automating away threats like this is to reduce the noise and increase the signal of more sophisticated attacks. It produces a heightened awareness of threats and allows you to better understand what types of attacks you are seeing day to day and provides valuable information that could help you understand what attackers are after. Data produced by these types of tools also supports threat models and risk analysis to better support your overall information security program.

Conclusions

This is just one of the many problems you face every day in the world of web application defense. There are many ways to solve this problem, but I encourage you to do so. There are some search engines that make validation difficult. For example, DuckDuckGo uses Amazon EC2 instances that don’t resolve back to DuckDuckGo and thus cannot follow the typical validation process. There are other search engines that present different challenges. If you do decide to give this module a try, let us know. If you find it useful, have questions, or would like to see improvements, let us know. We believe we can make the world a little safer by sharing, and we are hoping that this starts a broader conversation on handling bad robots.

CSRF Tokens with Restful API’s

Matt Konda No Comments

Our team was recently working on a test where we noticed that the application, which was a Single Page App (SPA) in front of a RESTful API was using session cookies but did not have Cross Site Request Forgery (CSRF) tokens.  When we discussed the issue with the development team, they indicated that in all their many years of experience writing API’s and fancy front ends, they had never used CSRF tokens with RESTful APIs.

The best source of information, maybe ironically, was this stack exchange post where a user posed the question and then answered it for themselves.  We think they got it right, but it wasn’t quite clear enough for our client’s developers who were quick to cite CORS as a mitigation.

This lead us to an interesting point, which is that for certain types of requests, eg. XHR (Ajax) requests where they go through CORS and pre-flight checks, it is true that CSRF tokens are less important.  However, simple POST requests do not go through pre-flight or CORS and therefore the CSRF token is still the only protection against CSRF.

The bottom line is that if you are using a cookie based session in your SPA and there are any endpoints that accept POST requests or GET requests that change data (an anti-pattern), then you should almost certainly have CSRF protection in place.

The whole idea behind CSRF is that the browser is a confused deputy and it will send your domain scoped cookie for domain-a.com to domain-a.com when a post to that domain happens, even if the form with the submit button is on domain-b.com.  This works just the same if you are a rich Single Page App talking to a RESTful API, provided the authentication is based on the session cookie.

This is just about what Burp generated for a proof of concept, we translated it a bit from JSON to url encoding to make it work:

<html>
  <body>
  <script>history.pushState('', '', '/')</script>
    <form action="https://target.wtf/api/things" method="POST" enctype="text/plain">
      <input type="hidden" name="thingy" value="Thing13"/>
      <input type="hidden" name="thingx" value="Thing14"/>
      <input type="submit" value="Submit request" />
    </form>
  </body>
</html>

The bottom line here is that we were surprised to find that developers working in an SPA thought CSRF was unnecessary.  Remember, your attackers are not constrained to use your application.

Note:  If you are using different authentication mechanisms, such as a key and secret with each request, where your RESTful endpoint is truly stateless and maybe the client is a command line application, it may be the case that you do not need CSRF protection.  However, if you are building a web application, you should think twice because … you guessed it, many of these secrets end up in domain scoped cookies that the browser will happily send along with the request and will work fine for authentication.

 

JASP 1.1

Matt Konda No Comments

In case you haven’t seen it, we’ve made some awesome progress in our JASP tool:

  • We added more advanced scoring and a “The One Thing™” screen which captures the one thing you should go fix.
  • With 1.1 we’re adding Reporting capabilities, including slice and dice by AWS service, date introduced, etc.
  • Updated product web site:  https://jasp.cloud and JASP itself is available at https://app.jasp.cloud now too.
  • Lots of new checks.

At this point, we feel great about the value the tool brings for our clients.  They get AWS security monitoring.  The advanced and partner level folks get support fixing issues.  For people that want to just check it out, there is a free tier.

I’m chomping at the bit to add code analysis, Azure cloud and others.  I’d love to hear your feedback on the kinds of cloud checks you would like to see and the integrations or workflows that would work best.  I really see the vision of a backbone for security automation, cloaked in a really valuable initial tool.

How we do code review

Matt Konda No Comments

Code Review Process

At Jemurai, we do a lot of code review. We do it for quality and we do it for security. We believe code review is one of the very best ways to understand the quality of your codebase, while providing contextual (its your application) feedback to developers about how to write better more secure code. We also believe that developers can learn to do awesome security code reviews. In this post, I’ll outline the basic thought process and approach I use when doing code reviews. Hopefully this post may help make it easier for people to do this kind of code review.

Overview of the Code Review Process

Typically, a code review involves several manual passes through a large number of files analyzing code following different trains of logic, checking for a large number of different kinds of issues. I almost never start at file A and work to file Z in that order based only on their names.

I use checklists extensively. Some of what I’m going to learn, I know right away looking at code. That will happen when you’ve been doing this as long as I have. But I still use checklists to ensure that I give each class of item appropriate attention. I do use tools to find specific potential issues. Grep is your friend, and its easy to make a catalog of things to look for.

grep -n -C 2 -R 'innerHTML' *

Still, the manual part of the review is essential. Perhaps most importantly because it gives me the ability to communicate with developers about how they are doing things in terms they really understand. But also because there are limits to automated analysis. Ask yourself how you can automatically check for “Insecure Direct Object Reference” or “Access Control”?

Strategy: Review Paths

As I indicated above, I usually start by thinking from a particular angle – what am I looking for in this code? Here are some examples of the paths I follow.

  • Overall design, abstraction, packaging, layering, etc.
  • Attack surface (exposed web endpoints for example)
  • Data flow
  • Trust boundaries
  • Data layer security
  • View layer security – roles, encoding
  • Resource usage (threads, apis, etc.)
  • Random sampling

In some cases it is possible (and desired) to manually review every line of code comprehensively.

Security Checklist Items

The following are among (but not necessarily all of) the items I specifically look at with security code reviews.

  • Input validation
  • Output encoding
  • Authentication
  • Authorization
  • SQL Injection
  • Direct Object Reference
  • Information Leakage
  • Error/Exception Handling
  • Secure Configuration
  • Encryption / Transport Layer Protection
  • Session Management
  • Appropriate logging / auditing

With the security items, I want to first see that a broad solution is in place to handle the potential issue. For example, I want to see output to be rendered in a browser going through encoding by default. For direct object reference, I want to see that the application is checking access to objects on all different types of access. Again, first I’m checking to see if there is a general approach or solution in place to solve the issue. If there is not, that’s a big problem.

Then, after verifying that a top level control is in place, I’m going to dive in and try to find examples where exceptions have been created and output is not being encoded properly. This is a little different in different technologies, but once you know how it might look you have a good idea what to look for. In a system using annotations and Spring security for authorization to modify objects, it becomes very straightforward to check all of the service methods for appropriate annotations.

With some classes of items, for example SQLi, I will literally look at every query generation method to try to catch potential issues. This is a factor of prevalence and severity – these types of issues are common and can cause big problems!

There is an OWASP Code Review project and that serves as a point of reference for checklist items during security code review. As with any resource, it should be looked upon critically and put in the proper context.

Quality Checklist Items

The following are items I look for in general quality reviews.

  • Source code design
  • Object Oriented principles (encapsulation, inheritance)
  • Application layering
  • Performance of code
  • Appropriate use of 3rd Party libraries
  • Consistency, readability, maintainability of code
  • Use of current and appropriate language features
  • Transaction strategy / caching
  • Use of threads
  • Query structure / performance
  • Appropriate unit tests

It is impossible to identify all quality criteria up front. Experienced developers make judgements based on their experience and the results for this review will be no different. The noted criteria are baseline examples of things that will be checked.

Communication

Did you know that communication is part of code review? I’ve definitely had security code reviews done where the deliverable was a big PDF report that said my code was crappy. Often, I didn’t understand the potential issues before the review and it left a very substantial amount of work to figure out what the real problem was and how to fix it.

In my code reviews, I establish a relationship with the developer early and work with them as I find things. I try to ask them whether my understanding of a potential issue is correct rather than point at a flaw. In some cases, I have missed a whole control layer that is being applied with an aspect or a framework I haven’t seen before. By asking, the developer gets a chance to think through their understanding of how the control should work and either admit that they missed something or point me in a direction to clarify. Also, I work hard to make sure that the resulting report of items includes solutions already discussed with the developers. That way the result feels more like an agreement and a step forward.

We found XSS, but here’s how we’re going to solve it and this is the timeframe.

Metrics

Code review metrics make it easier to put the results in context. Metrics like “LOC – Lines of Code” are commonly used but really don’t mean that much other than the size of the project. Identifying a small set of actionable metrics can be a helpful part of a code review process.

At Jemurai, we are working to standardize the metrics we provide as output for a code review. We hope this may help clients evaluate comparative severity of different projects. In theory, if these metrics can be standardized and have value, then they may be used in code reviews of open source projects … which itself might lead to an interesting broader code review project.

JASP 1.0.3

Matt Konda No Comments

Today we’re publicly releasing version 1.0.3 of JASP, our cloud security automation tool:  https://jasp.jemurai.com.

We think of it as “we’ll watch your back in the cloud“.   We currently work in AWS and check for common security issues across EC2, S3, and RDS and many other services.  You can sign up on the website and get free checks right there.  To get monitoring or extended reporting, we are offering several tiers of paid subscription plans.

We’re working hard to price it such that it is consumable by a general audience and not just hyper secure environments with huge budgets.  Part of our mission is to democratize access to security tools.

JASP is the culmination of a ton of work on the part of our team.  I want to pause to congratulate them for the accomplishment of building a tool that can help a lot of companies build more secure environments.  We’ve been through a lot.  Thanks, Team!

It is just the beginning.  Our roadmap includes tackling other new environments like Azure, GCP and even considering going after AppSec Automation.  We see the platform as a center of accessible security automation.

If you can, take a moment to check it out and give us feedback.  Its for you!  Happy Friday!

Security in the SDLC (Reboot)

Matt Konda No Comments

Today I was looking back for my blog posts about security in the SDLC from 2012-2016 and I realized that I had never migrated them forward to the new website when we updated.  Whoops!  So … in this post I want to recap in some detail what I’ve learned about security in the SDLC.

Every SDLC Is Different

Nearly every company we work with has a different version of how they build software.  Some are more Waterfally, others are more Agile.  Some are even DevOpsy.  Even within these broad categories, there is always variation.  At most mid and large sized companies, there are effectively more than one variation of SDLC being used.

For these reasons, when we build a model for integrating security into a company’s SDLC, one critical step is to stop and understand the SDLC itself.  I like to draw pictures at both a unit of work level and an overall process level.  We’ll present two then circle back and dive into the details.

Here is a generalized high level example.  The project timeline goes from the top left to the bottom right and the phases are represented by the segments.  Then we overlay security activities for each phase.

Here is an example of how we might represent a unit of work like a story and overlay security security activities.

It is very useful to have visual representations of the workflows to help communicate about what activities are expected when.

Every Company Has Security Strengths and Weaknesses

In theory, we can just identify best practices for security and everyone would do them.  In reality, we are constrained by:

  • The skills of the security team (and developers)
  • The technologies in use
  • The history of the program and the tools that have already been purchased
  • The budget and ability to change

We usually try to understand what a team is capable of and where their strengths are.  For example, some organizations are very focused on penetration testing.  Others have established training programs.  Others have strong static analysis tools.  Again the variation is the rule.  Therefore, our typical advice is to find the things that are realistic for your organization and then only overlay those onto your processes.

Discussing Risk

One important part of handling security within an organization is coming to an agreement across teams about how to discuss and manage risk.  This inherently involves engineering, security, business stakeholders and potentially even executives up the chain.  It is beyond the scope of this post to present a model for handling risk in general, but the presence of a process, engagement of the parties and a way to triage risks are important things to look for as you think about bringing risk into the conversation.

Capturing Security Requirements

There are a variety of ways that requirements are captured.  Sometimes they are in PRD’s (Product Requirements Documents).  Sometimes they are in stories.  The more we are able to explicitly capture security requirements, the better job we’re going to do meeting them.

Examples of security requirements on a story might include:

  • The following role is required to access this function
  • Access to this data should be logged
  • Values for coupon $ should only be positive

Again, we want to think about specific requirements in the context of each unit of work.  One way to help do that is to introduce a villain persona that we can refer to for inspiration as we imagine the abuse cases and how things can go wrong.

That being said, we also advocate for Baseline Security Requirements.  Baseline security requirements are requirements that exist across all of the stories for a given system.  Often they apply across different systems or services.  Examples of things covered in baseline security requirements might include:

  • Identity should be established from …
  • Security events should be logged to syslog
  • All connections should be over TLS
  • All user input should be validated and output encoded if shown in a web UI
  • All data should be encrypted at rest by X,Y,Z method based on data classification
  • How should Microservices authenticate to each other

Baseline security requirements are handled like Non Functional Requirements (NFR) which describe the operational qualities of a system rather than features.  An example of an NFR might be that a system should be able to handle 100,000 concurrent users.  This is something we need to know early and design for.  We think of Baseline Security Requirements in the same way.  If we present global expectations and constraints, it gives the developers the chance to choose appropriate frameworks, logging, identity, encryption, etc. as described above.

For both story and baseline security requirements, it is important that we identify these up front so that estimation includes security.  When estimates include security, developers have a chance of meeting security expectations.

Generally speaking, we advocate for identifying security requirements at almost every organization we work with.

Design Review and Surface Area Change

Throughout the development process, developers are continually adjusting major components, choosing 3rd party libraries, adding API endpoints and changing which systems interact with each other.  When we can identify these types of changes and trigger a discussion, it allows us to identify the right times to talk about security.

For example, when we add a new organization API endpoint, we want to ask who we expect to call it and what data it should expose.

If we add a logging or metrics framework like NewRelic, we might want to think about what data gets shared with NewRelic.

If we start to build something with Struts, we may want to step back and note that the library has a security history.

Some organizations have existing architecture teams that essentially gate the design and development process with processes to ensure supportability, health checks, etc.  This is a good place to inject design review.  In some cases however, this is too coarse grained and we’d rather see weekly or monthly checkpoints on design.

Testing

Some organizations are test forward organizations.  At these types of organizations, we advocate for security unit tests.  Security unit tests can be written for all kinds of security conditions:

  • Testing login, registration, forgot password flows.
  • Verifying authorization is implemented.
  • Injection.
  • XSS.
  • Logging / Auditing.

Generally, we recommend security unit/integration tests when organizations are already testing and their developers are capable of adding security tests.  The more elaborate the business logic and potential risk of fraud or other abuse through authorization scenarios, the more likely we are to push unit tests.

On the other hand, many organizations will not be able to do testing either because they don’t have a test culture or because their developers may not take an interest in security.

Checklists

At most clients, I recommend the following checklist for every story:

  • Prevented XSS through library that does output encoding by default
  • Parameterized any SQL
  • Identified sensitive data and encrypted at rest
  • Implementing proper authorization

At one client, we built this custom checklist into TFS issues so that developers could literally check those four boxes as they confirmed that they had handled these scenarios.

Checklists will only be effective in organizations where developers can value them and are trained.  That said, they are a low tech way to build security habits.

Code Review

Code review is something that we do both in large projects with some clients, and on a PR by PR basis in GitHub with others and on our own internal projects.  For organizations that use pull requests (PR’s) already, this can be a really good place to inject security.  Developers need training and time to do this properly, but in this case their existing processes support a very low friction incremental security activity.

Static Analysis

Static analysis is useful in some cases.  Its usefulness varies based on the language and scenario.

We typically recommend starting with open tools for languages/frameworks where they are well supported.  For example. bandit with python, brakeman with Ruby on Rails applications, sonarqube with Java apps.  Once you know your teams and processes can work with open tools, consider more advanced commercial tools.

Some gotchas with static analysis include:

  • False positives / Lack of prioritization of results
  • Can take a long time to run and therefore not work well as incremental check
  • Often very language specific
  • Rarely API friendly / Often expects devs to work in their interface

If your security team has a static analysis tool they like, consider integrating it gradually.

CI/CD (Continuous Integration/Continuous Delivery)

Continuous Integration is the process through which we automatically compile(build), test and prepare software based on many developers working on it concurrently.  Throughout the day, the build server is working on each commit to continuously integrate changes and rebuild.

Jenkins, Travis, CircleCI and others help us to make sure our software can be build portably and is tested regularly.  It helps us to identify problems as close to the point in time where we were coding them as possible.

Continuous Delivery takes CI a bit further and puts us in a position where we can deploy anytime – potentially many times a day.  CD is beneficial in that it usually means that we can fix issues in production faster than an organization not practicing CD.  That being said, it also suggests a level of automation that is conducive to additional security automation.  We might check internal service registries and ensure all services are running under SSL as part of a post deployment check.

We always recommend integrating tools into CI.  We contributed heavily to OWASP Glue for this type of integration work. This includes dependency checking, security unit tests and other types of more custom automation.  Seeing a project where only one workstation can build the software is an anti-pattern.  We also recommend continuous delivery because it means we can fix faster.

Dependency Analysis

Most software is built upon a set of 3rd party libraries.  Whether these are commercial or open source, sometimes there are vulnerabilities in the libraries we use.  In fact, for attackers, these libraries are particularly nice targets because a vulnerability in a library gives me the ability to target N users of that library.

Thus, as an engineering group, we need to make sure that our dependencies don’t have terrible vulnerabilities in them that we inherit by building on top of them.  We can do this by automating dependency checks.  We like npm, retire, bunder-audit and dependency-check for doing this.  We generally recommend using an open tool and building a process around it before adopting a commercial tool.

We also recommend having an explicit way to triage these items into tiers.

Decommission

An often forgotten way to improve security is to take applications offline.  Sometimes the cost benefit analysis just doesn’t support maintaining an application any more.  Other times the application isn’t used at all anymore.  Surprisingly often, these applications are still available and running – and not being updated.  The easiest way to reduce the attack surface is to just turn off the application.

Conclusion

The real conclusion of all of this is that there are a lot of different ways to take security activities and integrate them into the SDLC.  There is no one right way to do it.  This post presented some of the processes we use to engage and the activities we recommend.

 

The Cost of AppSec

Matt Konda No Comments

Application security is a weird field.  On the one hand, most practitioners know that it plays a critically important part of any organizations security posture.  We see real issues all the time, problems that cause our customers real losses.  On the other hand, as a wise security leader once said:

By the time the AppSec companies get to the table, 90% of the budget has been committed to AV and Firewalls.

Further, standards have a lot of trouble capturing Application Security.   I was recently diving into the NYDFS which mandates that companies have application security and found this broad statement:

Each Covered Entity’s cybersecurity program shall include written procedures, guidelines and standards designed to ensure the use of secure development practices for in-house developed applications utilized by the Covered Entity, and procedures for evaluating, assessing or testing the security of externally developed applications utilized by the Covered Entity within the context of the Covered Entity’s technology environment.

I mean, can  you say vague and open ended?  How do we know what to do based on that?  How do we go to our stakeholders and tell them we need to do … something?

To answer this question, I looked to the Verizon DBIR, various standards like NIST CSF, etc. and I realized that so many of the ways we think about those categories don’t fit into one area or another.  Consider a few areas that get called out:  MFA, stolen credentials, insider threats, malware.  Each and every one of these has an Application Security related angle.  As a software developer, I do networks, store data, think about identity and generally cross concerns.

So how do we step back and think about the value of application security?  Maybe we start by thinking about our risk models.

Do we have fraud paths in our applications?  What can we gain by stopping fraud?

Are we subject to standards?  Do we have partners that gate software purchases based on our security posture?  In that case, security is a part of our value for those partners.

In practice, models like the OWASP ASVS, OpenSAMM and others help to give us structure to think about application security.  They don’t necessarily help us know how to think about costs or appropriate expenditure…

So I guess its hard to answer this question.  We can say that we have “annualized loss expectancy” or other models … we can look at a company like Equifax and see the significant changes to that company’s stock price.  Generally, most models I’ve seen are speculative at best.

Through many projects building appsec programs, we have developed a practice that we can use to:

  • Size a program based on stakeholders, standards and goals
  • Inventory applications
  • Project costs and timelines

But the assumptions we make and the framework we use to do that is reactive and based upon stakeholder feedback.

How can we learn to build a better model that provides better proactive guidance for spending on application security?