Secure Source Code

1. Overview

Secure source code techniques are a set of practices that can be used to improve the security of source code. These techniques can help to identify and fix vulnerabilities in source code, prevent unauthorized access to source code, and protect source code from being modified.

Some common secure source code techniques include:

  • Linting: Linting is the process of checking source code for errors and stylistic issues. It is done by using a lint tool, which is a program that analyzes source code and identifies potential problems. Lint tools can be used to check for a variety of errors, including syntax errors, semantic errors, style errors, and security vulnerabilities.
  • Static application security testing (SAST): SAST is a type of security testing that analyzes source code, binary code, or byte code to identify security vulnerabilities. SAST tools can be used to find vulnerabilities in a variety of programming languages, including Go, Java, Python, C++, and C#.
  • License scanning: License scanning is the process of identifying the licenses of third-party software components used in a software application. This is important because it helps to ensure that the application complies with the terms of the licenses, which can help to avoid legal problems.

These techniques can be used to improve the security of source code at all stages of the software development life cycle. Linting can be used to identify errors early in the development process, SAST can be used to find vulnerabilities before the code is compiled or deployed, and license scanning can be used to ensure that the application complies with the terms of the licenses.

Using these techniques can help to improve the security of source code and to reduce the risk of security breaches.

What you will learn

This lab will focus on the tools and techniques to secure software source code.

  • Linting
  • Static Application Security Testing
  • License Scanning

All of the tools and commands used in this lab will be performed in the Cloud Shell.

2. Setup and Requirements

Self-paced environment setup

  1. Sign-in to the Google Cloud Console and create a new project or reuse an existing one. If you don't already have a Gmail or Google Workspace account, you must create one.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • The Project name is the display name for this project's participants. It is a character string not used by Google APIs. You can update it at any time.
  • The Project ID is unique across all Google Cloud projects and is immutable (cannot be changed after it has been set). The Cloud Console auto-generates a unique string; usually you don't care what it is. In most codelabs, you'll need to reference the Project ID (it is typically identified as PROJECT_ID). If you don't like the generated ID, you may generate another random one. Alternatively, you can try your own and see if it's available. It cannot be changed after this step and will remain for the duration of the project.
  • For your information, there is a third value, a Project Number which some APIs use. Learn more about all three of these values in the documentation.
  1. Next, you'll need to enable billing in the Cloud Console to use Cloud resources/APIs. Running through this codelab shouldn't cost much, if anything at all. To shut down resources so you don't incur billing beyond this tutorial, you can delete the resources you created or delete the whole project. New users of Google Cloud are eligible for the $300 USD Free Trial program.

Start Cloud Shell Editor

This lab was designed and tested for use with Google Cloud Shell Editor. To access the editor,

  1. Access your google project at https://console.cloud.google.com.
  2. In the top right corner click on the cloud shell editor icon

8560cc8d45e8c112.png

  1. A new pane will open in the bottom of your window
  2. Click on the Open Editor button

9e504cb98a6a8005.png

  1. The editor will open with an explorer on the right and editor in the central area
  2. A terminal pane should also be available in the bottom of the screen
  3. If the terminal is NOT open use the key combination of `ctrl+`` to open a new terminal window

Environment Setup

Set the GOPATH to a single directory to simplify commands used in this lab.

export GOPATH=$HOME/gopath

Create a directory to hold our work

mkdir -p workspace
cd workspace

Clone the source code repo

git clone https://gitlab.com/gcp-solutions-public/shift-left-security-workshop/source-code-lab.git
cd source-code-lab
export WORKDIR=$(pwd)

3. Linting

Linting is used to check common style-based mistakes or defects related to syntax. Linting assists security by providing a common syntax pattern across multiple teams that leads to faster code reviews, knowledge sharing and clarity of code.

Additionally, Linting identifies common syntax mistakes that can lead to common vulnerabilities such as improper or less efficient use of libraries or core APIs.

Install the staticcheck linking tool

 go get honnef.co/go/tools/cmd/staticcheck@latest

Run the Go Linter (staticcheck) in the project root directory

 staticcheck

Review the output

main.go:42:29: unnecessary use of fmt.Sprintf (S1039)

You get the error because http.ListenAndServe() accepts a String, and the current code uses Sprintf without passing variables to the string

Review the command exit status.

echo $?

In this case, since the command resulted in an error, the exit status will be 1 or greater. This is one method that can be used in a CI/CD pipeline to determine success/failure of the tool.

Edit the main.go file, and fix the code:

  • Comment out the line below LINTING - Step 1 inside the main() method, by adding leading slashes(//).
  • Uncomment the two lines directly below the LINTING - Step 2 inside the main() method, by removing the leading slashes.

Re-run staticcheck in the project root directory

staticcheck

The command should not return any results (i.e. an empty line.)

Inspect the exit status of the command.

  echo $?

In this case, since the command did not result in an error, the exit status will be zero.

4. Static Application Security Testing

AST/Static security testing - Provides static code analysis looking for common weaknesses and exposures ( CWEs)

Install the AST tool (gosec)

    export GOSEC_VERSION="2.15.0"
    curl -sfL https://raw.githubusercontent.com/securego/gosec/master/install.sh | \
          sh -s -- -b $(go env GOPATH)/bin v${GOSEC_VERSION}

Run gosec with policy file against the source code

gosec -conf policies/gosec-policy.json -fmt=json ./...

Output should be similar to this

{
    "Golang errors": {},
    "Issues": [
        {
            "severity": "HIGH",
            "confidence": "LOW",
            "cwe": {
                "ID": "798",
                "URL": "https://cwe.mitre.org/data/definitions/798.html"
            },
            "rule_id": "G101",
            "details": "Potential hardcoded credentials",
            "file": "/home/random-user-here/shift-left-security-workshop/labs/source-code-lab/main.go",
            "code": "31: \t// STEP 2: Change this and the reference below to something different (ie, not \"pawsword\" or \"password\")\n32: \tvar pawsword = \"im-a-cute-puppy\"\n33: \tfmt.Println(\"Something a puppy would use: \", username, pawsword)\n",
            "line": "32",
            "column": "6"
        }
    ],
    "Stats": {
        "files": 1,
        "lines": 89,
        "nosec": 0,
        "found": 1
    }
}

The tool has identified a potential issue: Potential hardcoded credentials

5. License Scanning

Licenses are important to security because they can legally require you to expose source code that you may not want to expose. The concept is called " copyleft" licenses that require you to expose source code if you use dependencies with those licenses.

Install golicense

mkdir -p /tmp/golicense
wget -O /tmp/golicense/golicense.tar.gz https://github.com/mitchellh/golicense/releases/download/v0.2.0/golicense_0.2.0_linux_x86_64.tar.gz
pushd /tmp/golicense
tar -xzf golicense.tar.gz
chmod +x golicense
mv golicense $(go env GOPATH)/bin/golicense
popd

Build the binary file

go build

Run the license check with the current policy file that does not allow "BSD-3-Clause" licenses

golicense policies/license-policy.hcl hello-world

NOTE: This should fail with similar output:

 🚫 rsc.io/sampler    BSD 3-Clause "New" or "Revised" License
 🚫 rsc.io/quote      BSD 3-Clause "New" or "Revised" License
 🚫 golang.org/x/text BSD 3-Clause "New" or "Revised" License

Modify the policy file policies/license-policy.hcl to move the "BSD-3-Clause" from the deny list to the allow list.

Re-run the license check

golicense policies/license-policy.hcl hello-world

NOTE: This should succeed with similar output:

    ✅ rsc.io/quote      BSD 3-Clause "New" or "Revised" License
    ✅ rsc.io/sampler    BSD 3-Clause "New" or "Revised" License
    ✅ golang.org/x/text BSD 3-Clause "New" or "Revised" License

6. Congratulations

Congratulations, you finished the codelab!

What you have learned

  • Tools and techniques to secure source code

Last update: 3/23/23