Engineering

Live Coding a New Glue Task at AppSecUSA

Matt Konda No Comments

At AppSecUSA, OWASP Glue, a project we contribute heavily to, was asked to present in the project showcase.  I put together an overview talk about how the tool is architected and what we use it for.  Then, we added a new task live during the talk.  I thought that was enough fun that it was worth blogging about.  I would like to start by acknowledging Omer Levi Hevroni, of Soluto, who has also contributed and continued support for Glue over the past year +.

Why Glue?

We started working on Glue because we found that most security tools don’t integrate all that cleanly with CI/CD or other developer oriented systems.  Our goal is always to get the checking as close to the time of code authorship as possible.  Further, we thought that having it wrap open source tools would make them more accessible.  Philosophically, I’m not that excited about tools (see earlier post) but we should definitely be using them as much as we can provided they don’t get in our way.  Ultimately, we wrote Glue to make it easy to run a few security tools and have the output dump into Jira or a CSV.

Glue Architecture

So we defined Glue with the following core concepts:

  • Mounters – these make the code available.  Could be pulling from GitHub or opening a docker image.
  • Tasks:  Files – these analyze files.  Examples are ClamAV and hashdeep.
  • Tasks:  Code – these are some level of code analysis.  Some are first class static tools, others are searching for dependencies or secrets.
  • Tasks:  Live – these are running some kind of live tool like Zap against a system.
  • Filters – filters take the list of findings and eliminate some based on whatever the filter criteria are.  An example is limiting ZAP X-Frame-Options findings to 1 per scan instead of 1 per page.
  • Reporters – reporters take the list of findings and push them wherever you want them to end up.  JIRA, TeamCity, Pivotal Tracker, CSV, JSON, etc.

Live Coding

OK, so a common task is to say

“Hey, this is cool but I want to do this with a tool that Glue doesn’t yet support.”

Great.  That should be easy.  Let’s walk through the steps.  We’ll do this with a python dependency checker:  safety.

Set Up the Task

A good way to start a new task is to copy an existing one.  In this case, we’re going to do a python based task so let’s copy the bandit task and alter to match:

require 'glue/tasks/base_task'  # We need these libraries.  The base_task gives us a report method.
require 'json'
require 'glue/util'
require 'pathname'

# This was written live during AppSecUSA 2018.
class Glue::SafetyCheck < Glue::BaseTask  # Extend the base task.

Glue::Tasks.add self  # Glue is dynamic and discovers tasks based on a static list.  This adds this task to the list.
includeGlue::Util

def initialize(trigger, tracker)
  super(trigger, tracker)
  @name="SafetyCheck"                             # This is the name of the check.  -t safetycheck (lowered)
  @description="Source analysis for Python"
  @stage= :code                                   # Stage indicates when the check should run.
  @labels<<"code"<<"python"                       # The labels allow a user to run python related tasks.  -l python
end

Now we have the start of a class that defines our SafetyCheck task.

Run the Tool :  Safety Check

Here we just need to implement the run method and tell the task how to call the tool we want to run.  In this case, we want it to create json.  The resulting code is:

def run
  rootpath = @trigger.path
  @result=runsystem(true, "safety", "check", "--json", "-r", "#{rootpath}/requirements.txt")
end

The @trigger is set when the Task is initialized (see above) and includes information about where the code is.  We use that to know where the path that we want to analyze is.  Then we use one of the provided util methods runsystem to invoke safety check with the parameters we want.

Note that we are putting the result in the @result instance variable.

Parse the Results

Once the tool runs, we have the output in our @result variable.  So we can look at it and parse out the JSON as follows:

 def analyze
    puts @result
    results = clean_result(@result)
    begin
      parsed = JSON.parse(results)
      parsed.each do |item|  
        source = { :scanner => @name, :file => "#{item[0]} #{item[2]} from #{@trigger.path}/requirements.txt", :line => nil, :code => nil }
        report "Library #{item[0]} has known vulnerabilities.", item[3], source, severity("medium"), fingerprint(item[3]) 
      end 
    rescue Exception => e
      Glue.warn e.message
      Glue.warn e.backtrace
      Glue.warn "Raw result: #{@result}"
    end
  end

Here, we call a clean_result method on the result first.  You can look here for detail, but it is just pulling the warnings that the tool emits that make the output not valid JSON.  We do this to make sure the JSON is parseable for our output.  This is a common issue with open source tools.  I don’t underestimate the value of making these things just work.

The magic here is really in the two lines that set the source and then report it.  The source in Glue terms is the thing that found the issue and where it found it.  In this case, we’re setting it to be our Task (SafetyCheck) and the library name in the output from file containing the dependencies. (requirements.txt)

The report method is supplied by the parent BaseTask class and takes as arguments:  description, detail, source, severity and fingerprint.

def report description, detail, source, severity, fingerprint
    finding = Glue::Finding.new( @trigger.appname, description, detail, source, severity, fingerprint, self.class.name )
    @findings << finding
end

You can see if you look closely that we set all of the severities to Medium here because safety check doesn’t give us better information.  We also use the supplied fingerprint method to make sure that we know if we have a duplicate.  You can also see that the result of calling report is that we have a new finding and the finding is added to the array of findings that were created by this task.  We get the trigger name, the check name, a timestamp, etc. just by using the common Finding and BaseTask classes.

Making Sure the Tool is Available

In addition to run and analyze the other method we expect to have in our Task is a method called supported?.  The purpose of this method is to check that the tool is available.  Here’s the implementation we came up with for safety check, which doesn’t have a version call from the CLI.

 def supported?
    supported=runsystem(true, "safety", "check", "--help")
    if supported =~ /command not found/
      Glue.notify "Install python and pip."
      Glue.notify "Run: pip install safety"
      Glue.notify "See: https://github.com/pyupio/safety"
      return false
    else
      return true
    end
  end

The idea here is to run the tool in a way that tests if it is available and alerts the user if it is not.  Graceful degredation as it were…

The Meta

Here is the code from the Tasks ruby file that runs all the tasks.

if task.stage == stage and task.supported?
  if task.labels.intersect? tracker.options[:labels] or      # Only run tasks with labels
    ( run_tasks and run_tasks.include? task_name.downcase )  # or that are explicitly requested.

    Glue.notify "#{stage} - #{task_name} - #{task.labels}"
    task.run
    task.analyze
    ...

Here you see the supported?, run and analyze methods getting called.  You also see the labels and tasks being applied.  Its not magic, but it might look weird when you first jump in.

Conclusion

We wanted to create a new task.  We did it in about 20 minutes in a talk.  Of course, I wrote the code around it so it was easy.  But it does illustrate how simple it is to add a new task to Glue.

If you want to see this check in action, you can run something like:

bin/glue -t safetycheck https://github.com/DefectDojo/django-DefectDojo

We’re getting the Docker image updated, but once available you can run:

docker run owasp/glue -t safetycheck https://github.com/DefectDojo/django-DefectDojo

We hope people can digest and understand Glue.  We think it is an easy way to get a lot of automation running quickly.  We even run a cluster of Kubernetes nodes doing analysis.  This in addition to integrating into Jenkins builds or git hooks.  Happy Open Source coding!!!

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

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.

 

Product Security in Github Issues

Matt Konda No Comments

As I’ve mentioned here in the past, we started working on a product in 2018 and we are getting really close to launching it more openly where people other than our initial (friendly) alpha customers can use it.   The reaction has been awesome and we’re encouraged.

As I looked at our project, I realized we needed to step back and really confirm we had our basics covered.  Now mind you, we’re all security oriented developers so I’m not saying these things weren’t done by our team – but I will say that even I, as a leader and someone who gets on a soapbox a lot about pushing left, had not explicitly emphasized or required these things as first class features yet.

So I thought I’d share a bit of detail about our thinking here.  We basically wanted to take the simplest possible approach to something that would work.  So I brainstormed a bit on some general items we always care about and added github issues for them.

Note that this not an exhaustive list.  We have more detailed requirements about authorization for example in each story.  We also have items to check for things like sql and code injection.  But I wanted to start simple for this discussion.

  • The Twitter password exposure notification and the emails I received as I dutifully reset my password inspired #36 here.  Basically, if we notify people properly we can let them help us identify issues if they happen.
  • Implementing two factor is pretty basic now and should be required for most if not all public apps.  We will think about social logins as well, but we’re not sure if that is relevant yet.
  • Knowing about both failed password attempts and successful attempts after a lot of failed attempts is interesting and will allow us to see brute forcing.
  • Setting security headers is easy and should be automatic.  Let’s make sure we do it.
  • Force SSL is self explanatory.
  • Verifying that we have secure and httpOnly set for session cookies is easy once we think of it.
  • We’re using Vue.js for the front end.  Let’s stop and make sure it is handling malicious script inputs the way we think and ensure that our API’s are encoding data as needed.
  • If we’re storing sensitive information, let’s talk through and document key management and algorithms as a team.
  • Let’s build a threat model that we can use on an ongoing basis for each different app component.  We’re thinking about threat dragon but I generally just use a mind mapping tool.  I think I’ll write a whole post about these.

Anyway, if you’re working on any kind of web application, most of these apply in one shape or form.  Reach out to me if you have questions.  Happy building!!!

Announcing Jemurai Security Automation

Matt Konda one comments

Its been an exhilarating few weeks.  I had to remind myself to take a breath and blog today.

What’s new-ish is that, we have a core team working on a new platform for security automation.  It extends the work we’ve done with Glue and other ideas taken from a great sample of client consulting engagements.  Across all of those engagements it just never felt like any solution was complete or as intuitive as it should have been.  We were always bending rules to live in Jenkins or to write custom scripts to check things that maybe aren’t that unique.

I’ve tried to always remind my team:  get meta.  What’s the problem behind the problem?  That vuln isn’t the problem.  Its the SDLC that allows the vuln to be introduced and not reviewed or noticed that is the problem.

Frankly, as a team we all started to think that all the tooling we’re using for DevOps and Security Automation is all too opinionated.  None of it is at its root there to be the backbone of a flexible solution.  Usually the existing tooling is pushing you into a particular vendors security tool.

We don’t have a combination of a rich inventory, accessible through an API, combined with a flexible way to do things with source code, containers, live systems, clouds in an abstracted way that can be assembled to build a better security automation solution.  The opportunity presented itself to start working on it and as a team we couldn’t be more excited to be building the next generation of tooling.  We’ve got prototypes flying that look at this problem in a whole new way.

If you’re interested in hearing more, are struggling with security automation, or have ideas you want to share to help us, I would personally love to hear from you.  We’re also actively looking for beta testers.  Catch me at matt at the company domain dot com.