diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..11951ce --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,84 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL - Manual Example" + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + schedule: + - cron: '34 3 * * 0' + +jobs: + analyze: + name: Analyze + # Runner size impacts CodeQL analysis time. To learn more, please see: + # - https://gh.io/recommended-hardware-resources-for-running-codeql + # - https://gh.io/supported-runners-and-hardware-resources + # - https://gh.io/using-larger-runners + # Consider using larger runners for possible analysis time improvements. + runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }} + permissions: + # required for all workflows + security-events: write + + # only required for workflows in private repositories + actions: read + contents: read + + strategy: + fail-fast: false + matrix: + language: [ 'javascript-typescript' ] + # CodeQL supports [ 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' ] + # Use only 'java-kotlin' to analyze code written in Java, Kotlin or both + # Use only 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + + # Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v3 + + # ℹī¸ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + + # If the Autobuild fails above, remove it and uncomment the following three lines. + # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + + # - run: | + # echo "Run, Build Application using script" + # ./location_of_script_within_repo/buildscript.sh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/truff.yaml b/.github/workflows/truff.yaml new file mode 100644 index 0000000..95a116f --- /dev/null +++ b/.github/workflows/truff.yaml @@ -0,0 +1,23 @@ +name: TruffleHog Secrets Scan + +on: + push: + branches: + - main + pull_request: + +jobs: + test: + runs-on: ubuntu-latest + name: Test for Secrets + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Secret Scanning + uses: trufflesecurity/trufflehog@main + with: + base: "" + head: ${{ github.ref_name }} + extra_args: --debug diff --git a/.talismanrc b/.talismanrc new file mode 100644 index 0000000..a579c46 --- /dev/null +++ b/.talismanrc @@ -0,0 +1,13 @@ +fileignoreconfig: +- filename: part1/README.md + checksum: 296322f09011c5d5842a59367be6128832786fab03e2473eaaf7bd1d0401b007 +- filename: part2/VulnerableAppTwo/keys/rsaexample.pem + checksum: cc5872d91bc99346267659d9bc7bb2189547f6742edf25bf7b447b04af65d440 +- filename: part2/README.md + checksum: dece0d209b83000453119ab7a500465654ed9d5a96a5fbdeb7738a5dd17560d9 +- filename: README.md + checksum: d5a9d7377587552896b7ce67ebe4da86bec5c9c753e16c120c7622df01b3a956 +- filename: horusec-config.json + checksum: 727c5016cd645828fba85e4e02a5d6d4b0d762a881aadb695333c973b6c03e27 +threshold: medium +version: "" diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6d281ea --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Tweag + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..cecf6c0 --- /dev/null +++ b/README.md @@ -0,0 +1,65 @@ + +# Template Repository - Shifting Security Left a Hands On Workshop + +The following repository contains training material workshops on shifting security left. + +This workshop is held at venue `X` on `DATE` at `TIME`. + +## Workshop Outline + +*Shifting Security Left a Hands On Workshop* provides participants with an introduction to baking security into the software development process and leveraging DevSecOps tooling to support this. + +Attendees will learn about setting up a local development environment which includes security tools such as IDE plugins. Students will then progress into learning how to use DevSecOps pipelines to detect security issues such as accidentally committed secrets. + +The workshop will then wrap up with tips on how to handle secure deployments and a look to what the future holds in this space. + +## Pre-setup Phase + +In order to fully participate in this workshop you will need a GitHub account. + +You can obtain this by signing up at http://www.github.com. + +Students will be able to sign up for a .edu account which comes with some added bonuses, such as being able to setup private repositories for free. + +Once your account is setup, you will need to `Fork` and `Clone` this repository. + +A full guide to setting up the tooling for this workshop can be found in the Part 1 README file. + +[Part 1 - Security within the development environment](https://github.com/tweag/dev-sec-ops-workshop/tree/main/part1#part-1---security-within-the-development-environment) + + +## Part 1: Security within the development environment + +Attendees will learn to integrate security tools and pre-commit hooks into their development environment thus enhancing code security off the bat: + +1. 3rd party plugin integration. In this part of the talk we explore third-party tooling that can be integrated into the IDE to aid in linting and SAST. An example here includes the SonarLint plugin. We also look at CodeQL and GitHub Copilot [Part 1 - Module1: IDE Integration](https://github.com/tweag/dev-sec-ops-workshop/tree/main/part1#module-1-ide-integration) + +2. Setting up pre-commit hooks to aid in security will be explored. This includes tools such as AWS Labs git-secrets and Talisman. [Part 1 - Module2: pre-commit Hooks](https://github.com/tweag/dev-sec-ops-workshop/tree/main/part1#module-2-pre-commit-hooks) + +3. Git ignores. Git ignore files are a great way of preventing config files which may contain secrets, and other undesirable files such as .zips accidentally being committed. In this portion of the talk we provide practical examples of using .gitignore to aid in security. [Part 1 - Module 3: Preventing accidental commits](https://github.com/tweag/dev-sec-ops-workshop/tree/main/part1#module-3-preventing-accidental-commits) + + +## Part 2: Repository Scanning + +Here we cover some repository scanning techniques, including secrets scanning and vulnerability detection, using tools like GitHub's dependabot and Tartufo. + +1. Secrets scanning. A demonstration of how secret scanning can be performed in the source code. This includes examples of Tartufo/TruffleHog, GitHub's tooling and Horusec. [Part 2 - Module 4:Secrets Scanning](https://github.com/tweag/dev-sec-ops-workshop/tree/main/part2#module-4secrets-scanning) + +2. Handling secrets in GitHub. GitHub provides users the ability to store secrets such as API keys securely within the SCM, and pull these out at deployment time. Here participants learn the basics of the environment within GitHub and how to leverage GitHub native secret storage mechanisms. We will also discuss other options for storing secrets and pulling them into CI/CD pipelines [Part 2 - Module 5: Handling secrets in GitHub](https://github.com/tweag/dev-sec-ops-workshop/tree/main/part2#module-5handling-secrets-in-github) + +3. Detecting security vulnerabilities within the repository. Students are introduced to the concept of detecting security vulnerabilities in the source code repository. A general overview of techniques and approaches is given, as well as those specific to GitHub.[Part 2 - Module 6:Detecting Security vulnerabilities](https://github.com/tweag/dev-sec-ops-workshop/tree/main/part2#module-5handling-secrets-in-github) + +4. Vulnerable dependency detection. GitHub's dependabot provides a mechanism for analyzing the dependencies associated with a project and understanding if they contain security vulnerabilities. Walkthrough of dependabot is performed. [Part 2 - Module 7:Vulnerable dependencies](https://github.com/tweag/dev-sec-ops-workshop/tree/main/part2#module-7vulnerable-dependencies) + +5. Static analysis. GitHub Advanced Security contains a GitHub native SAST tool built on CodeQL. This section of the class walks through its feature sets and how it can be integrated into GitHub actions. This section of the talk will also cover Horusec and how it cane be used in the same capacity.[Part 2 - Module 8:Static Analysis](https://github.com/tweag/dev-sec-ops-workshop/tree/main/part2#module-8static-analysis) + +6. Branch protection and pull request gating mechanisms. The penultimate topic covered is how branch protection rules and PR gating mechanisms can leverage SAST tools to block pull requests that fail security checks.[Module 9:Branch protection rules](https://github.com/tweag/dev-sec-ops-workshop/tree/main/part2#module-9branch-protection-rules) + +7. SBOMs. A final note on SBOMs. These can be used to extract a Software Bill of Materials from your applications stored in GitHub. [Part 2 - Module 10:SBOMs Software Bill of Materials](https://github.com/tweag/dev-sec-ops-workshop/tree/main/part2#module-10sboms-software-bill-of-materials) + +## Wrap-up + +Discussion of future trends in this space. + +Recap of what we've learned + diff --git a/horusec-config.json b/horusec-config.json new file mode 100644 index 0000000..1c43274 --- /dev/null +++ b/horusec-config.json @@ -0,0 +1,145 @@ +{ + "horusecCliCertInsecureSkipVerify": false, + "horusecCliCertPath": "", + "horusecCliContainerBindProjectPath": "", + "horusecCliCustomRulesPath": "", + "horusecCliDisableDocker": false, + "horusecCliEnableCommitAuthor": false, + "horusecCliEnableGitHistoryAnalysis": false, + "horusecCliEnableInformationSeverity": false, + "horusecCliFalsePositiveHashes": [], + "horusecCliFilesOrPathsToIgnore": [ + "*tmp*", + "**/.vscode/**", + "**/deployments/**", + "**/.git/**", + "**/.pyre/**", + "**/.venv/**", + "**/*.env", + "**/.mypy_cache/**", + "**/htmlcov/**", + "**/tests/**", + "**/frontend/**", + "**/Makefile**" + ], + "horusecCliFilterPath": "", + "horusecCliHeaders": {}, + "horusecCliHorusecApiUri": "http://0.0.0.0:8000", + "horusecCliJsonOutputFilepath": "", + "horusecCliMonitorRetryInSeconds": 15, + "horusecCliPrintOutputType": "text", + "horusecCliProjectPath": "", + "horusecCliRepositoryAuthorization": "00000000-0000-0000-0000-000000000000", + "horusecCliRepositoryName": "blog", + "horusecCliReturnErrorIfFoundVulnerability": false, + "horusecCliRiskAcceptHashes": [ + ], + "horusecCliSeveritiesToIgnore": [ + "INFO" + ], + "horusecCliTimeoutInSecondsAnalysis": 600, + "horusecCliTimeoutInSecondsRequest": 300, + "horusecCliToolsConfig": { + "Bandit": { + "istoignore": false, + "imagepath": "" + }, + "Brakeman": { + "istoignore": false, + "imagepath": "" + }, + "Eslint": { + "istoignore": false, + "imagepath": "" + }, + "Flawfinder": { + "istoignore": false, + "imagepath": "" + }, + "GitLeaks": { + "istoignore": false, + "imagepath": "" + }, + "GoSec": { + "istoignore": false, + "imagepath": "" + }, + "HorusecCsharp": { + "istoignore": false, + "imagepath": "" + }, + "HorusecDart": { + "istoignore": false, + "imagepath": "" + }, + "HorusecJava": { + "istoignore": false, + "imagepath": "" + }, + "HorusecKotlin": { + "istoignore": false, + "imagepath": "" + }, + "HorusecKubernetes": { + "istoignore": false, + "imagepath": "" + }, + "HorusecLeaks": { + "istoignore": false, + "imagepath": "" + }, + "HorusecNodeJS": { + "istoignore": false, + "imagepath": "" + }, + "NpmAudit": { + "istoignore": false, + "imagepath": "" + }, + "PhpCS": { + "istoignore": false, + "imagepath": "" + }, + "Safety": { + "istoignore": false, + "imagepath": "" + }, + "SecurityCodeScan": { + "istoignore": false, + "imagepath": "" + }, + "Semgrep": { + "istoignore": false, + "imagepath": "" + }, + "ShellCheck": { + "istoignore": false, + "imagepath": "" + }, + "TfSec": { + "istoignore": false, + "imagepath": "" + }, + "YarnAudit": { + "istoignore": false, + "imagepath": "" + } + }, + "horusecCliToolsToIgnore": [], + "horusecCliWorkDir": { + "go": [], + "netCore": [], + "csharp": [], + "ruby": [], + "python": [], + "java": [], + "kotlin": [], + "javaScript": [], + "leaks": [], + "hcl": [], + "php": [], + "c": [], + "yaml": [], + "generic": [] + } +} diff --git a/part1/README.md b/part1/README.md new file mode 100644 index 0000000..3ba2fa0 --- /dev/null +++ b/part1/README.md @@ -0,0 +1,664 @@ + +# Part 1 - Security within the development environment + +In Part 1 we look at a variety of technologies that can be used to improve security in the SDLC at the development environment level. + +A number of technologies are used during this part of the workshop including: + +1. SonarLint: https://docs.sonarsource.com/sonarcloud/improving/sonarlint/ + +2. VSCode: https://code.visualstudio.com/ + +3. SonarCloud: https://sonarcloud.io/ + +4. GitHub: https://github.com/ and GitHub CodeQL: https://codeql.github.com/docs/codeql-overview/ + +5. AWS Labs git-secret: https://github.com/awslabs/git-secrets + +6. Talisman: https://github.com/thoughtworks/talisman + +7. .gitignore files: https://git-scm.com/docs/gitignore + +8. BFG repo-cleaner: https://rtyley.github.io/bfg-repo-cleaner/ + +These can be downloaded/setup in advance of completing the workshop, or as you go. Some applications such as BFG also require you to be able to execute Java on your machine. + +Examples in this workshop use commandline prompts that should work on Linux, MacOS and Windows Subsystem for Linux (WSL) + +The first account you will need if you have not created it already is a GitHub one. Use the link above to sign up. + +Once this created, you can now fork this repository. + +Follow the instructions below, to fork https://github.com/tweag/dev-sec-ops-workshop + +https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo + +If you do not have Git installed locally, also ensure you set this up: + +https://git-scm.com/book/en/v2/Getting-Started-Installing-Git + +Once both of these tasks are complete, you can clone the repository: + +`git clone ` + +With the code now located on your local machine, you are ready to start. + + +## Module 1: IDE Integration + +The first part of the workshop will cover security within the Integrated Development Environment (IDE). + +In this example we will add plugins to the IDE in order to detect security issues on the fly. + +### SonarLint Plugin + +We will be using a plugin called SonarLint. SonarLint can be obtained from: + +https://docs.sonarsource.com/sonarcloud/improving/sonarlint/ + +Supported IDEs include: + +1. JetBrains IDEs (IDEA, CLion, GoLand, WebStorm etc.) + +2. Visual Studio + +3. VS Code + +4. Eclipse + +During this workshop we use VS Code for examples, but this can be replaced with the supported IDE +of your choice. + +SonarLint has a number of features including: + +* Connects with SonarCloud +* Rules and issues +* Quick Fixes +* Secrets Detection +* Vulnerability detection + +Download and install the plugin into your IDE before proceeding. + +For this demo we also recommend creating a SonarCloud account. You can do this via your GitHub user at: + +https://sonarcloud.io/ + +SonarLint will still work without a SonarCloud account, but has fewer features. + +Once you have an account, make a note of your `Organization` name from the `Organizations` tab in SonarCloud. + +Next generate a token. Go to the `Security` tab and generate a new token, call it `dev-sec-ops-demo`. + +In your IDE, select the `Add SonarCloud Connection` option. On this screen you can add the token, and `Organization Key`. + +Using SonarLint we can now detect security issues in the code base. + +Open up the `vuln.ini` in the `part1` folder in your IDE. + +![Part 1 - SonarLint](./img/sonarlint.png "SonarLint example") + +You should see that under the `aws_key_id` key id value is a wavy line. If you hover over this, or select the `PROBLEMS` tab, an error should be present: + +```console + +Make sure the access granted with this AWS access key ID is restricted + +``` + +This indicates that SonarLint has picked up on the key being hardcoded into the file. + +Let's now look at some of the other findings in the JS file: + +* Use of `var` instead of `let` or `const` +* Useless variable assignments (note also the use of the local DB) +* Inclusion of an `alert` which could leak sensitive information +* Use of the `debugger` statement, which SonarLint flags for security concerns + +If you select the example `var sqlresult` where `var` being used a small lightbulb will appear, clicking this will allow you to quickly fix the issue. + +Try this and you will see it replaced the `var` with `let` and removes the detected issue. We're going to leave the other issues in place now, so we can demonstrate how to fix them using some of the other tools in this workshop. + +That wraps up using SonarLint. You can use it to quickly detect parts of your codebase that may have syntax errors, styling problems, and a subset of security issues. + +Let's take a look at an alernative tool to SonarLint which can also detect issues in the codebase. + +### CodeQL + +We're now going to switch over to using another tool that can aid in detecting security issues in our source code. This tool is called CodeQL. + +The first step is to install the CLI tools prior to adding in the VS Code plugin. + +GitHub provides instructions here: + +https://docs.github.com/en/code-security/codeql-cli/getting-started-with-the-codeql-cli/setting-up-the-codeql-cli + +And we will provide a quick overview here on what you need to do, to get the CLI installed and setup. + +1. Head over to the CodeQL Bundle release page: https://github.com/github/codeql-action/releases + +2. Download the latest version of the bundle for your OS. These bundles are listed under `Assets` + +3. Unzip the bundle. + +4. Once the zip is extracted the CodeQL CLI will be available for use. You may want to add this to your `PATH` so you can execute the CLI with a simple `codeql` command. You can read more about adding CodeQL to your `PATH` here: https://docs.github.com/en/code-security/codeql-cli/getting-started-with-the-codeql-cli/setting-up-the-codeql-cli#2-extract-the-zip-archive + +5. Test the codeql command, you should see something similar to: + +```console + +Create and query CodeQL databases, or work with the QL language. + +GitHub makes this program freely available for the analysis of open-source software and certain other uses, but it is not itself free software. Type codeql --license to see the license +terms. + + --license Show the license terms for the CodeQL toolchain. +Common options: + -h, --help Show this help text. + -v, --verbose Incrementally increase the number of progress messages printed. + -q, --quiet Incrementally decrease the number of progress messages printed. +Some advanced options have been hidden; try --help -v for a fuller view. +Commands: + query Compile and execute QL code. + bqrs Get information from .bqrs files. + database Create, analyze and process CodeQL databases. + dataset [Plumbing] Work with raw QL datasets. + test Execute QL unit tests. + resolve [Deep plumbing] Helper commands to resolve disk locations etc. + execute [Deep plumbing] Low-level commands that need special JVM options. + version Show the version of the CodeQL toolchain. + generate Commands that generate useful output. + github Commands useful for interacting with the GitHub API through CodeQL. + pack Commands to manage QL packages. + diagnostic [Experimental] Create, process, and export diagnostic information. +``` + +6. We can now test that codeql is correctly setup to generate a database. Use the following command: + +```console + +codeql resolve qlpacks +``` + +You should now see it output something similar to this example: + +```console + +codeql-csharp-consistency-queries (/workshop/qlpacks/codeql/csharp/ql/consistency-queries) +codeql-csharp-tests (/workshop/qlpacks/codeql/csharp/ql/test) +codeql-go-consistency-queries (/workshop/qlpacks/codeql/go/ql/consistency-queries) +codeql-java-consistency-queries (/workshop/qlpacks/codeql/java/ql/consistency-queries) +codeql-swift-tests (/workshop/qlpacks/codeql/swift/ql/test) + +``` +Now we have the commandline tool in place we are going to generate a database off of our vulnerable code. This database is an Abstract Syntax Tree representation of the code combined with some metadata about the code base. GitHub provides and overview on the database and using it in VS Code here: https://codeql.github.com/docs/codeql-for-visual-studio-code/exploring-the-structure-of-your-source-code/ + + +```console + +./codeql database create --language=javascript-typescript --source-root ../dev-sec-ops-workshop/part1 ../javascript-database + +``` + +This will output: + +```console + +Initializing database at /workshop/javascript-database. +Running build command: [] +[2024-03-22 09:20:15] [build-stdout] Single-threaded extraction. +[2024-03-22 09:20:15] [build-stdout] Extracting /workshop/dev-sec-ops-workshop/part1/src/vuln.js +[2024-03-22 09:20:15] [build-stdout] Done extracting /workshop/dev-sec-ops-workshop/part1/src/vuln.js (327 ms) +[2024-03-22 09:20:15] [build-stderr] No externs trap cache found + +... + +Finalizing database at /workshop/javascript-database. +Running TRAP import for CodeQL database at /workshop/javascript-database... +Importing TRAP files +Merging relations +Finished writing database (relations: 13.32 MiB; string pool: 4.78 MiB). +TRAP import complete (4s). +Finished zipping source archive (247.38 KiB). +Successfully created database at /workshop/javascript-database. + +``` +We now have a database generated from our code to work with. However before we can use it via the VS Code IDE we will need to install the plugin. + +You can find basic installation instructions for VS Code here: + +https://codeql.github.com/docs/codeql-for-visual-studio-code/setting-up-codeql-in-visual-studio-code/ + +Once you have the plugin installed, we can setup a CodeQL workspace. + +In this workshop we will use the `Starter Workspace`. + +We're going to need to get the CodeQL libraries and queries and can clone this from GitHub into a new directory on your machine: + +```console + +git clone --recursive git@github.com:github/vscode-codeql-starter.git + +``` + +Once this has cloned we need to switch back to VS Code. + +Once in the IDE select `File > Open Workspace from File` + +Navigate to the folder where you checked out the `vscode-codeql-starter` repository and select the `vscode-codeql-starter.code-workspace` file. + +This will now load the workspace in visual studio. Save any changes if prompted to the `vuln.js` file you edited. + +In the left-hand menu you should now see a list of queries. + +![Part 1 - CodeQL](./img/codeql.png "CodeQL example") + +Scroll down and select the `example.ql` from under the `codeql-custom-queries-javascript` to see an example of a CodeQL query. + +This demonstrates the format that CodeQL queries are written in. If you scroll down further to the `ql` folder and expand it you'll see a section called `javascript`. + +Under this folder you will find the configuration of JavaScript queries for detecting issues with the code base. + +In order to test the queries against our codebase we can now load our database via the `DATABASES` panel in VS Code. + +Select the `Choose Database from Folder` option, and select the database we created from the source code. + +![Part 1 - CodeQL DB](./img/codeqldb.png "CodeQL Database example") + +You can filter the queries in the `QUERIES` panel to only display JavaScript ones, by selecting `JavaScript` from the `LANGUAGE` panel. This should make the query list easier to navigate. + +From the `QUERIES` list navigate down to find `javascript / ql > src > LanguageFeatures > DebuggerStatement.ql`. A triangle will appear. This is the run icon, which will execute the query against the database. Click this. + +CodeQL will now run the query against our source code. It might take a few seconds to compile, optomize and execute. You should now see it finds the `debugger` statement in the source code. + +![Part 1 - CodeQL Query Example](./img/codeqldebugger.png "CodeQL Debugger example") + +CodeQL has a huge number of queries available for JavaScript. You can scroll through the list and try running some of them to see what you can find. + +That wraps up the basics of using CodeQL to build a database of our code, and manually run scans against it to find issues. When we move on to Part 2 you will see CodeQL in action within GitHub Advanced Security, where it provides SAST support. + +### GitHub Copilot (optional hands on) + +For those of you with student accounts or paid GitHub accounts you can integrate Copilot into your IDE and use the power of GenerativeAI to detect and remediate issues. + +Copilot is GitHub's new tool to integrate GenAI into the development process allowing you to generate code and unit tests on the fly. It can also be used to help detect security vulnerablities in source code. + +To register for a plan refer to: + +https://github.com/features/copilot/plans + +A quick start guide is provided here: https://docs.github.com/en/copilot/quickstart + +For this course, we are interested in installing the Copilot extension in VS Code. + +1. Install the plugin from the marketplace: https://marketplace.visualstudio.com/items?itemName=GitHub.copilot + +2. If prompted, open VS Code + +3. Under the `Extension: GitHub Copilot` tab, select `Install` + +4. You will now be prompted to grant permissions to authorize Copilot. + +With Copilot installed you can follow along with the steps below. + +1. Open the Chat Window + +2. Enter the following prompt "Can you highlight security issues in my code?" + +3. Co-pilot will execute your query and spit out a response similar to the following: + +```console + +SQL Injection: In the saveToDatabase method, you're directly inserting the blogPost properties into the SQL query. This makes your application vulnerable to SQL injection attacks. + +``` +```javascript +static saveToDatabase(blogPost) { + const sql = `INSERT INTO blog_posts (title, content, author) VALUES ('${blogPost.title}', '${blogPost.content}', '${blogPost.author}')`; + } +``` + +4. We can now ask it how to remediate this issue by asking "How can I prevent SQL injection in my code?" + +Co-pilot will now spit out an example of how the code can be refactored. + + +```console +To prevent SQL injection, you should use parameterized queries or prepared statements. This ensures that user input is always treated as literal data and not part of the SQL command. Here's how you can modify your saveToDatabase method to use parameterized queries: +``` + +```javascript + static saveToDatabase(blogPost) { + const sql = `INSERT INTO blog_posts (title, content, author) VALUES (?, ?, ?)`; + // Pretend database call + console.log(`Executing SQL: ${sql}`); + var db = window.openDatabase("sqlcachedb", "1.0", "Cache result", 200000); + db.transaction(function(tx){ + tx.executeSql(sql, [blogPost.title, blogPost.content, blogPost.author], function(tx, results){ + console.log("Data inserted successfully"); + }, function(tx, error){ + console.log("Error occurred while inserting data"); + }); + }); + } +``` + +```console +In this code, the ? are placeholders for the actual values. The values are passed in as an array in the second argument to executeSql. This ensures that the values are properly escaped, preventing SQL injection attacks. +``` + +Much like we did with SonarLint, we can fix issues by selecting the wavy lines and clicking the small icon that pops up. Select the line with the `var db = window.openDatabase` issue. + +From the menu, select the `Fix using Copilot. + +You'll now be presented with an option to replace `var` with `let` like we did in the previous example. Select this and save your change. + +Using these mechanism we can have Copilot present us with a set of fixes for the issues it detected, as well as the problems that SonarLint and CodeQL highlighted. + +So in addition to detecting and fixing issues from the IDE, what else can we do to harden our development process? + +## Module 2: Pre-commit Hooks + +Having demonstrated how we can fix security issues as we go, we next look at mechanisms to prevent code with vulnerabilities, such as hard coded secrets being commited +to the repository. To do this we will show you how to use pre-commit hooks. + +### AWS Labs git-secrets + +In the `.ini` file you will remember we have provided an example of a hard coded (dummy) AWS API key. + +The AWS git-secrets tool can be used to scan files locally for hardcoded keys in order to alert the engineer. + +You can clone the repository from the following location: + +https://github.com/awslabs/git-secrets + +The `README` explains a number of mechanisms to install git-secrets based upon your OS. + +For each repository you will need to install the hooks. Once git-secrets is installed, in this repository install the hooks via: + +```console + +git secrets -- install + +``` + +Next let's register common AWS patterns for scanning: + +```console + + git secrets --register-aws + +``` + +It is also possible to add specific strings that represent common patterns e.g. keys in a repo: + +```console + +git secrets --add '[A-Z0-9]{20}' + +``` + +We can run a scan as follows: + +```console + +git secrets --scan + +``` + +You should now see output similar to the following: + +```console +[ERROR] Matched one or more prohibited patterns + +Possible mitigations: +- Mark false positives as allowed using: git config --add secrets.allowed ... +- Mark false positives as allowed by adding regular expressions to .gitallowed at repository's root directory +- List your configured patterns: git config --get-all secrets.patterns +- List your configured allowed patterns: git config --get-all secrets.allowed +- List your configured allowed patterns in .gitallowed at repository's root directory +- Use --no-verify if this is a one-time false positive +``` + +Edit this README file, and make a change here, change status: `incomplete` to `complete`. + +`status: incomplete` + + +Commit this change to the text file. You should now see the pre-commit hook kick in. +It will warn you that a secret is present in the repository. + +We are now going to look at a tool that can do this on a much broader scale. + + +### Talisman + +We've seen how AWS simple but effective tool can be used to create pre-commit hooks and catch +API keys being commited to the repository. + +The next tool we will look at is Talisman. You can find it at the following GitHub repository: + +https://github.com/thoughtworks/talisman + +Talisman is capable of scanning git changesets to ensure secrets and other sensitive information is +not added to the repository. This includes not only AWS API Keys, but SSH keys, tokens, passwords and similar. + +Open up the `README` file in the GitHub repository and follow the installation steps for your OS. + +Once installed we can configure a stand alone pre-commit hook for our repository. + +Run the following command: + +```console +echo "talisman -g pre-commit" >> .git/hooks/pre-commit +``` + +Much like with the AWS tool, the pre-commit hook will now act as a blocker to commiting secrets to the code base. + +We can ignore false positives using the `.talismanrc` file. You can see an example in the root of this project. + +Here we have told it to ignore the `README` file, since it contains words that trigger a false positive. + +```console +Talisman Scan: 3 / 3 <-----------------------------------------------------------------------------------------------------------------------------------------------------------> 100.00% + +Talisman Report: ++-----------------+--------------------------------+----------+ +| FILE | ERRORS | SEVERITY | ++-----------------+--------------------------------+----------+ +| part1/README.md | Potential secret pattern : | low | +| | not added to the repository. | | +| | This includes not only AWS API | | +| | Keys, but SSH keys, tokens, | | +| | passwords and similar. | | ++-----------------+--------------------------------+----------+ + + +If you are absolutely sure that you want to ignore the above files from talisman detectors, consider pasting the following format in .talismanrc file in the project root + +fileignoreconfig: +- filename: part1/README.md + checksum: 7bc8a740923be465f9f54f83fef533d0e93fa2b978350fc006d2094f2d47741d +version: "" + +``` + +We can also ignore low severity findings, by adding the following line to our .talismanrc + +```YAML + +threshold: medium + +``` + +Of course, this introduces the risk that true positives could be added to the code base. + +Talisman can also be run as a command line tool. This will scan the target directory for secrets and output a JSON file with a list of findings. + +To run a scan you can type: + +```console + +talisman -s + +``` + +The output will be added to: + +```console + +talisman_report/talisman_reports/data + +``` + + +Give this a try and navigate to the folder. Open the JSON file in your IDE to examine it. + + +## Module 3: Preventing accidental commits + + +We've seen a couple of methods to catch secrets from being commited to the repository. We can also prevent whole files being added. + +Much as we saw with the `.talismanrc` file where we could configure talisman to ignore false positives, we can use a `.` file to prevent whole file types being commited to git. + +To do this, we use the `.gitignore` file. Our next task will be to demonstrate how they work. + +### .gitignore files + +Within the repository we have provided an example ignore file called `example.gitignore`. + +Rename the `example.gitignore` file in the root of this directory to `.gitignore`. + +Now try copying the `vuln.ini` file as a `.env` file. + +```console +cp vuln.ini .env +``` + +Now run: + +```console +git status +``` + +You should see the `.env` file isn't present e.g. + +```console +Untracked files: + (use "git add ..." to include in what will be committed) + .gitignore +``` + +This is because the `.gitignore` file is preventing this file type from being added. + + +If you edit the `.gitignore` file to remove the `.env` line, then run `git status` again, it will be listed e.g. + + +```console +Untracked files: + (use "git add ..." to include in what will be committed) + .env + .gitignore +``` + +As you can see this simple technique can be used to block production configuration files with secrets located in them from being commited and pushed to GitHub, thus exposing them. + +We can also use this technique to prevent binary files, PDFs or other file types that are undesirable being commited to the repository. + +So what happens if we have already commited a file, or somebody not following best practices adds one? Well there are techniques we can use to clean it up. + +Let's look at an example. + + +### BFG to clean up accidental commits + +In some cases a file may already exist in the commit history that we need to remove. This could have been due to a disabled pre-commit hook, a file or pattern that wasn't caught, or a file added prior to the introduction of DevSecOps processes. + +In order to clean up historical commits we can use BFG. Let's try an experiment to demonstrate this. + +If you haven't downloaded/installed BFG yet, you can find it here: + +https://rtyley.github.io/bfg-repo-cleaner/ + +The `bfg` command used later in this example is an alias for calling the BFG .jar file: + +```console + +java -jar bfg.jar + +``` + +You can add an alias to your `.bash_profile` or `.zshrc` file: + +```console + +alias bfg='java -jar bfg.jar' +``` + +Or if you want, replace the `bfg` references below with the direct call to the `.jar` file shown above. + +With BFG setup, we can now try and experiment. + +We previously modified our `.gitignore` file so that we can now commit the `.env` file which contains secrets. + +We are now going to demonstrate how a mistake can happen that needs to be cleaned up. Add and commit this modified `.gitignore` file now: + +```console +git commit -m"Adding the .env file so we can demonstrate BFG" +``` + + +Now push this commit to your fork. + +```console +git push +``` + +We should now see the `.env` file is present, along with all the leaked secrets! + +When a mistake like this happens in real life there are two steps we would want to take: + +1. Remove the secrets from the repository + +2. Rotate them so they are now obsolete + +Let's now use BFG to scrub the file from the repository: + +```console +bfg --delete-files .env my-forked-repo.git +``` + +BFG will now remove the `.env` file we added. + +We can check this was successful by checking the log: + +```console +git log + +git show HEAD +``` + +Once you are happy the file is cleared, go ahead and push the changes back to your fork: + +```console +git push +``` + +So we just saw a simple approach to doing file clean up! + + +## Conclusion + +You've now completed Part 1. Here we setup our development environment and accounts and we learned about: + +1. IDE plugins to detect secutity issues + +2. Pre-commit hooks to prevent adding passwords and API keys to GitHub + +3. Using .gitignore files to bock whole file types being commited + +4. A technique to clean up accidentally commited files + +In Part2 we are now going to see how the next line of defense in the source control management system and CI/CD pipelines can perform similar and complementing tasks. + diff --git a/part1/example.gitignore b/part1/example.gitignore new file mode 100644 index 0000000..4c49bd7 --- /dev/null +++ b/part1/example.gitignore @@ -0,0 +1 @@ +.env diff --git a/part1/img/codeql.png b/part1/img/codeql.png new file mode 100644 index 0000000..1a743e6 Binary files /dev/null and b/part1/img/codeql.png differ diff --git a/part1/img/codeqldb.png b/part1/img/codeqldb.png new file mode 100644 index 0000000..cd3ce60 Binary files /dev/null and b/part1/img/codeqldb.png differ diff --git a/part1/img/codeqldebugger.png b/part1/img/codeqldebugger.png new file mode 100644 index 0000000..4935019 Binary files /dev/null and b/part1/img/codeqldebugger.png differ diff --git a/part1/img/sonarlint.png b/part1/img/sonarlint.png new file mode 100644 index 0000000..3119651 Binary files /dev/null and b/part1/img/sonarlint.png differ diff --git a/part1/src/vuln.js b/part1/src/vuln.js new file mode 100644 index 0000000..8f59d4e --- /dev/null +++ b/part1/src/vuln.js @@ -0,0 +1,98 @@ +// Example: Vuln.js +// DISCLAIMER: This code contains intentional security vulnerabilities as examples based on the OWASP Top 10. +// DO NOT use this code in production or any secure application. +// It's for educational purposes only as part of BSides Tampa 2024 workshop +const net = require('node:net'); + +class User { + constructor(username, password) { + // A2:2021 – Cryptographic Failures + // Storing passwords in plain text + this.username = username; + this.password = password; + } + + // A5:2021 – Security Misconfiguration + // Insecure default configuration + static getDefaultUser() { + return new User('defaultUser', 'password123'); + } +} + +class BlogPost { + constructor(title, content, author) { + this.title = title; + this.content = content; + this.author = author; + } + + // A3:2021 – Injection + // Vulnerable to SQL Injection + static saveToDatabase(blogPost) { + const sql = `INSERT INTO blog_posts (title, content, author) VALUES ('${blogPost.title}', '${blogPost.content}', '${blogPost.author}')`; + // Pretend database call + console.log(`Executing SQL: ${sql}`); + var sqlresult = db.exec(sql) + var db = window.openDatabase("sqlcachedb", "1.0", "Cache result", sqlresult); + + alert("Submission successful"); + } +} + +class Account { + constructor(user) { + this.user = user; + } + + // A1:2021 – Broken Access Control + // Method allows any user to change any password + changePassword(username, newPassword) { + // Logic to change password without verifying the current user's permission + let gensalt = random_salt(); + console.log(`Password for ${username} changed to ${newPassword}`); + + } +} + +// A7:2021 – Identification and Authentication Failures +// Weak authentication mechanism +function authenticateUser(username, password) { + // Pretend user lookup + if (username === 'admin' && password === 'admin') { + console.log('Authentication successful'); + const info =`name=${username}`; + Cookies.set('jsSession', encodeURIComponent(info), { expires: 365 }); + return true; + } else { + console.log('Authentication failed'); + Debug.write("User was: " + username); + Debug.write("Password was: " + password); + debugger; + return false; + } +} + +// Psuedo-random number generated salt +function random_salt() { + return Math.random(); +} + +// Start the server +function startApp() { + const server = net.createServer(function (socket) { + socket.write('Echo server\r\n'); + socket.pipe(socket); + }); + server.listen(5000, '0.0.0.0'); +} + + + +// Example usage +const user = new User('tampaadmin', '123456'); +const blogPost = new BlogPost('Vulnerable JavaScript', 'This post details some common vulnerabilities.', 'tampaadmin'); +BlogPost.saveToDatabase(blogPost); +const account = new Account(user); +account.changePassword('tampaadmin', 'newpassword123'); +authenticateUser('admin', 'admin'); + diff --git a/part1/vuln.ini b/part1/vuln.ini new file mode 100644 index 0000000..c710d3b --- /dev/null +++ b/part1/vuln.ini @@ -0,0 +1,48 @@ +; BSides Tampa 2024 - Example of an insecure .ini configuration file illustrating potential security vulnerabilities + +[database] +; Using default credentials can lead to unauthorized access (Security Misconfiguration) +username = admin +password = password + +[server] +; Insecure communication can be intercepted (Sensitive Data Exposure) +use_https = false +; Running the server as a superuser could lead to privilege escalation (Security Misconfiguration) +run_as_superuser = true + +[logging] +; Storing sensitive data in logs can lead to information leakage (Sensitive Data Exposure) +log_sensitive_information = true +; Not limiting log file size can lead to denial of service by filling up disk space (Denial of Service) +log_file_max_size = 0 ; 0 for unlimited + +[error_handling] +; Detailed error messages can lead to information disclosure (Security Misconfiguration) +show_detailed_errors = true + +[features] +; Enabling unnecessary features can increase the attack surface (Security Misconfiguration) +enable_debug_mode = true +enable_remote_access = true + +[session_management] +; Weak session management can be exploited for session hijacking (Broken Authentication) +session_timeout = 0 ; 0 for never +use_secure_cookies = false + +[file_upload] +; Allowing unrestricted file uploads can lead to arbitrary code execution (Injection) +allow_any_file_type = true +max_file_size = 0 ; 0 for unlimited + +[api] +; Exposing sensitive endpoints without proper authentication (Broken Access Control) +allow_anonymous_access = true + +[third_party_services] +; Storing API keys in plain text can lead to their disclosure (Sensitive Data Exposure) +aws_key_id = "ASIAY34DZKCOKMUTVV8B" +aws_api_key = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" + + diff --git a/part2/README.md b/part2/README.md new file mode 100644 index 0000000..11346aa --- /dev/null +++ b/part2/README.md @@ -0,0 +1,529 @@ + +# Part 2: Repository Scanning + + +For this part of the workshop we've provide two vulnerable applications to work with. + +One is Java based, and the second is JavaScript. These can be found under: + +1. VulnerableApp (Java) + +2. VulnerableAppTwo (JavaScript) + +We will start by looking at how secrets scanning tools can be used against these applications. + + +## Module 4:Secrets scanning + +We can use both GitHub native and CI/CD orientated tools to scan for secrets in our repository. In this part of the workshop we are going to look at three options: + +1. GitHub Native secrets scanning + +2. TruffleHog (and Tartufo) which can be executed from GitHub Actions + +3. Horusec, which we will briefly walk through. + + +### GitHub Native Secrets Scanning + +GitHub provides us with an built-in mechanism to scan for secrets. This includes the ability to scan for custom patterns as well as common key formats, such as AWS API keys. + +Configuration of Secrets scanning in GitHub, including the configuration of custom patterns is found under `Settings > Code security and analysis`. + +![Part 2 - Secrets scanning](./img/secretsconfig.png "Secrets configuration") + +We've already added the regex for detecting the private key. But let's see how this works. + +Select the `PEM` detection rule and open it up. Under here is the `secret format` + +```console +-----BEGIN PRIVATE KEY-----(.|\s)*?-----END PRIVATE KEY----- +``` + +This regex will detect files such as our `.pem` key and then add an alert to the `Security` tab. + +You can create a new pattern here to detect other secret types. Hit the back button and go back to the previous screen. + +Select the `New pattern` option and then use the following regex to test for AWS API keys. You may remember we did something similar in Part 1: + +```console + +"[A-Za-z0-9/+=]{40}" + +``` + +![Part 2 - Secrets Regex](./img/secretsregex.png "Secrets Regex") + +If you want to test the regex, you can do this by pasting in our dummy example key from `vuln.ini` in Part 1, and creating a dry run. + +Select the `Publish pattern` button. Congrats, you have now added your own custom secrets detection. + +We can find detected secrets under the `Security > Secret scanning` option. Switch to this screen. + +If you select the PEM detection finding, you will find some helpful information including: + +1. The finding + +2. Remediation steps + +3. The detected location + +If you wish, you can remove the key from your forked repository and commit and push the change. Remember we can use the steps provided in `part1` to remove a file from Git. + +Re-visit this screen and then choose an option from the `Close as` drop down to close out the finding, for example `Revoked` + +Congrats, you've written a detection rule and closed out a finding. + +Let's look at other secrets scanning tools and how they can be integrated with GitHub Actions. + + +### TruffleHog, Tartufo and GitHub Actions + +TruffleHog is a tool that can be used to scan for secrets in source code. GoDaddy maintains their own version of this, which has a wrapper adding extra configuration functionality called Tartufo. For this part of the workshop we will use a pre-setup version of TruffleHog which is located in the `.github/workflows/` folder. + +After you have experimented with TruffleHog, we will setup Tartufo to demonstrate how tooling can be added to our CI/CD pipelines + +As you will now see, we have an Action configured that uses the TruffleHog tool to scan for secrets in the code base. + +Under the `Actions` tab, look for an event that has trigged `.github/workflows/truff.yaml ` + +You will notice this has a red circle with an X in it (❌), which means the job failed. + +Open this workflow run up. + +You will see a stage called `Test for Secrets` - this has executed a scan against the code base to test for secrets. + +Here we can see it detected the JDBC connection in VulnerableApp (in addition to the .pem key file) + +```console + +test: part2/src/vulnerableapp.java#L16 +Found unverified JDBC result 🐷🔑 + +``` + +If we open up this file, we can see the offending line of code: + +```java + +Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/test?user=sqluser&password=sqlpassword"); + +``` + +The hardcoded credentials in the DB connection have been flagged. + +Setting up a new Action from the marketplace is fairly staight forward. If we want to compare the results of TruffleHog and Tartufo we can do this by adding the +the Action following the instructions here: https://github.com/marketplace/actions/tartufo-scan + +To add the new workflow create a new `.github/workflows/tartufo.yml` file. + +Add the following configuration to this: + +```yaml + +on: + push: + branches: + - main + pull_request: + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Tartufo Scan + uses: godaddy/tartufo-action@4.1.0 + +``` + +Commit this change and push it to GitHub. + +The Action will now execute and you should see it under the `Actions` tab. When it runs it will fail. + +We can drill into the `Action` by selecting its workflow from the left hand menu and then selecting the latest run. + +When this loads, select the failed stage and it will open up. + +There's a lot of information displayed here, but if you dig through it you will see that the AWS API key and the `.pem` file have been discovered. + +```console + +Commit hash: 00d808190419d4a6ee0886d616d568e206792b58 +Branch: main +diff --git a/part2/VulnerableAppTwo/keys/rsaexample.pem b/part2/VulnerableAppTwo/keys/rsaexample.pem +new file mode 100644 +index 0000000..523c04d +--- /dev/null ++++ b/part2/VulnerableAppTwo/keys/rsaexample.pem +@@ -0,0 +1,28 @@ + +``` + +So now we have two tools running in our Actions workflows to detect for secrets and can compare the output of them both. + +You've also seen how easy it is to add a marketplace action to your repository. There are numerous Actions available in the marketplace including integrations with major security vendor tooling. + +Let's try another example. + +### Horusec + +Horusec is a tool that bundles together multiple security scanners. We can use it locally or within a CI/CD pipeline. Its full fledged feature set leverages containers to run multiple tools and then aggregates the findings. You can read more about it at: + +https://github.com/ZupIT/horusec + +Let's try a quick experiment using the Action from the [market place](https://github.com/marketplace/actions/horusec). + +We can copy this into a new YAML file at `.github/workflows/horusec.yml`: + +```yaml +name: Horusec Security Scan + +on: [push] + +jobs: + horusec-security-scan: + runs-on: ubuntu-latest + name: Run Horusec Security Scan + steps: + - name: Check out code + uses: actions/checkout@v4 + + - name: Run Horusec Security Scan + id: run_horusec + uses: fike/horusec-action@v0.2.2 + with: + arguments: -c=horusec-config.json -p ./ +``` + +Commit this and push it back up to GitHub. + +Once the workflow has finished executing, we can then drill into the results. You'll see that unlike Tartufo and TrufflHog we also have a lot of other security findings. We'll revist these later in the SAST section of this workshop. For now though, we can drill down into the findings and see that Horusec has also found the `.pem` keyfile: + +```console + +Language: Leaks +Severity: CRITICAL +Line: 41 +Column: 0 +SecurityTool: HorusecEngine +Confidence: MEDIUM +File: /github/workspace/part2/README.md +Code: -----BEGIN PRIVATE KEY-----(.|\s)*?-----END PRIVATE KEY----- +RuleID: HS-LEAKS-12 +Type: Vulnerability +ReferenceHash: 943157e96e40574c92c9313d40a13689dc4c5b176d54e156c8e7c5f1a2ddd8ee +Details: (1/1) * Possible vulnerability detected: Asymmetric Private Key +Found SSH and/or x.509 Cerficates among the files of your project, make sure you want this kind of information inside your Git repo, since it can be missused by someone with access to any kind of copy. For more information checkout the CWE-312 (https://cwe.mitre.org/data/definitions/312.html) advisory. + +``` + +So in this section of the workshop we saw multiple examples of tools we can use to scan for leaked credentials, passwords, API Keys and similar. + +For a real project we would now want to go through the steps of fixing the code to remove the hardcoding, rotating the credentials and removing the detected ones from the repository. If you would like, try removing the `.pem` file with `git rm `, committing the change and pushing it back up to GitHub. + +You can now view the output from the various Actions you have setup to see what's changed. + +So we have figured out how to detect secrets leakage, but what about if we need to safely use our example AWS key in Part 1 or similar for deployment in CI/CD pipelines? + +Let's now take a look at where we might store the credentials to avoid this happening again. + + +## Module 5:Handling secrets in GitHub + +We can avoid hard coding secrets into files through using a secrets manager. GitHub comes with one which can be accessed under + +`Settings > Secrets and variables > Actions` + +We can create a new secret for our project by selecting the `New repository secret` button. + +Give you secret a name e.g. `demo_secret`. + +Add a `Secret` - let's use something simple like `password` for this example. Of course, this is not a good option for a real life password! + +This secret should now be visibile: + + +![Part 2 - Secret in GitHub](./img/reposecret.png "Secret in GitHub") + +This secret can be used now in Actions pipelines, to avoid having to hard code it into a file. + +Let's try this out. + +Create a new Action in your `.github/workflows` directory called `usingsecrets.yml`. To this file add the following code: + +```yaml + +name: Example Using Secrets + +on: + push: + branches: + - main + pull_request: + +jobs: + secrets: + runs-on: ubuntu-latest + name: Demo Using Secrets + steps: + - name: Echo Out The Secret + env: + bsides_secret: ${{ secrets.demo_secret }} + run: echo "$bsides_secret" + +``` + +Commit this and push it up to GitHub, and then check out the Actions tab. + +You will see that it executed. A nice feature is, Actions is smart enough to prevent the `echo` statement from leaking our password: + +```console +Run echo "$bsides_secret" +*** +``` + +Our password in this example has been replaced with `***`. + +So that's a basic guide to how we can detect secrets from GitHub's native tooling and GitHub Actions using a third party tool, as well as use GitHub's secrets storage mechanism. + +We will now take a look at how we can detect security vulnerabilities across our code base. + +## Module 6:Detecting secutity vulnerabilities + +GitHub supports a number of mechanisms for handling security vulnerabilities including: + +1. SAST + +2. Dependency Analysis + +3. Secrets scanning + +4. SBOMS + +We can also add a security policy to our repository so that contributors know how to responsibly report findings. To do this, navigate to the `Security` tab. + +From here we can select the `Set up a security policy` button. Next select the `Start setup` button. + +Let's add a dummy policy in. You can add anything you like for now. + +Save this. + +If you return to the `Security overview` you will now see the `Security policy` is enabled + +That was pretty simple! Let's move onto seeing how we can detect vulnerabilities. + +## Module 7:Vulnerable dependencies + +In the forked repository you will notice that a pull request has been created. This is because GitHub has detected we have a vulnerable dependency in our `pom.xml` and `package.json` files. + +Click on the first pull request in the list, and you can find more information. + +We can see that merging this pull request fixes 4 dependabot alerts in relation to Log4J: + +1. Remote code injection + +2. Incomplete fix + +3. Improper Input Validation and Uncontrolled Recursion + +4. Improper Input Validation in Apache Log4j + + +If you merge in this PR it will fix the issue. If you are unfamiliar with this concept, GitHub provides an overview here: https://docs.github.com/en/code-security/dependabot/working-with-dependabot/managing-pull-requests-for-dependency-updates + +You can also try this with the JavaScript related dependency issues to fix the vulnerabilities. + +Later in this workshop we will be looking at how you can extract the list of dependencies as an SBOM. Now we have fixed vulnerabilities in our repository, let's take a look at the application source code again. + + +## Module 8:Static Analysis + +In Part 1 we ran CodeQL locally and executed a query against the codebase. This is great for doing local research and experimentation. But what if we want to scan changes to the code on the fly, and from multiple commiters? That's where CodeQL integrated into GitHub comes in handy. With this feature we can run CodeQL as a GitHub Action and scan any code that is a supported language pushed into the repository for vulnerabilities. + +In this example we have enabled CodeQL by default in this repository. Let's take a look at the configuration. + +Go to the `Actions` tab in GitHub and you will see there are two CodeQL workflows. + +![Part 2 - Actions Workflows](./img/codeqlexample.png "Workflows") + +When setting up CodeQL you can manually add a file or configure it with default values directly in GitHub. + +From the workflows list, the top item is an example of one that was created directly in GitHub wthout adding a `codeql.yml` file. + +The next one down, uses the `codeql.yml` file. + +Let's see if CodeQL has detected any vulnerabilities. Navigate to: + +`Security > Code Scanning` + +Under this option you should see listings including from Part 1 or this course and Part 2. For example: + +`Database query built from user-controlled sources` + +This was detected in `part2/VulnerableAppTwo/src/VulnerableAppTwo.js` on line `33`. + +If you open up the finding, you will see it has flagged: + +```javascript + const user = await User.findOne({ username: username, password: password }); +``` + +Expanding the finding will show a large amount of detail around the issue including: + + +1. A description + +2. A recommendation + +3. An example + +4. Some references for further reading. + +There are multiple fixes you can try in the list to resolve the issue. + +If this was a false positive we could select a value from the `Dismiss alert` drop down. Or, if we wantd to create a backlog item to fix the issue +we can create a new GitHub Issue using the button in the top right. + +Try selecting one of the fixes. Apply it to your code locally and commit and push it back up to GitHub. Did this resolve the issue? + +You may also want to check the Action you created earlier that included Horusec. Compare this to CodeQL and see if the issue was detected in both places, and now shows as being resolved. + +We've now seen how we can use SAST in GitHub, let's take a look at how we can prevent code being merged into branches unless a user has permission, or our SAST scans are successful. + + +## Module 9:Branch protection rules + +The `main` branch represents our mainline of development, and would likely be deployed to a production envrionment. It is therefore important that only certain users have permission to add code to it, and also that the code that is merged in is clean and free of security vulnerabilities. + +We can protect our `main` branch through a couple of mechanisms. You should see a message similar to this, within your forked repo: + +```console +Your main branch isn't protected + +Protect this branch from force pushing or deletion, or require status checks before merging. View documentation. +``` + +The first option is to select the `Protect this branch` button from the repository next to the above message. + +The second option is to configure the branch protection rule through the settings. To do this, follow these steps: + +1. Select `Settings` from the top menu + +2. On the left select `Branches` + +3. You should see a button called `Add banch protection rule` + +4. When you select this, a menu will load. + +5. You can set the `Branch name pattern` to `main` + +6. Select `Require a pull request before merging` + +7. Next select `Require status checks to pass before merging` + +8. Select `Create` + +We now have rules in place that force a pull request and all checks to pass before merging. + +We can also ensure that only certain users and groups in GitHub can merge to certain branches. This is achieved through adding a `CODEOWNERS` file. + +You can learn more about these here: + +https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners + +When the file is added, then individuals/groups listed in the `CODEOWNERS` files will be tagged with a request to review the pull request. + +Adding the file is simple. In the `.github` directory within your repository, add the file: + +```console + +touch .github/CODEOWNERS + +``` + +Open this file in your editor and add the following: + +```console + +# When someone opens a pull request that +# modifies JS files, your user will be requested for a review. +*.js @my-user + +``` +Replace `@my-user` with your GitHub user. + +Commit this change and push it to the remote repository. + +We can now return to our branch protection rules and edit them to also use the `CODEOWNERS` file. + +Include the requirement `Require review from Code Owners` + +Well done, you've just completed a basic guide to how you can enforce checks on branches to improve security in the SDLC. + +Let's now take a look at Software Bill of Materials (SBOM). + +## Module 10:SBOMs (Software Bill of Materials) + +Our final task is going to be to extract the SBOM from our project. An SBOM is a nested inventory of the components within an application. You can think of it as an ingrediants list of sorts. US government ageencies are now mandated to obtain an SBOM from their software vendors and internal engineering teams in order to validate the products security. So being familiar with the term and process is helpful. + +Within GitHub the SBOM can be found under `Insights > Dependency graph`. + +You'll notice on this screen that if you haven't fixed any of the security issues associated with dependencies these will be flagged. + +![Part 2 - SBOM and Dependencies](./img/sbom.png "SBOM and Dependencies") + +We can extract the SBOM by selecting the `Export SBOM` button on the top left. This will download a JSON file to your local machine. + +Here's an example of what part of the file looks like + +```json + +{"SPDXID":"SPDXRef-DOCUMENT","spdxVersion":"SPDX-2.3","creationInfo":{"created":"2024-03-20T18:26:13Z","creators":["Tool: GitHub.com-Dependency-Graph"]},"name":"com.github.tweag/dev-sec-ops-workshop","dataLicense":"CC0-1.0","documentDescribes":["SPDXRef-com.github.tweag-dev-sec-ops-workshop"] + +... + +{"relationshipType":"DEPENDS_ON","spdxElementId":"SPDXRef-com.github.tweag-dev-sec-ops-workshop","relatedSpdxElement":"SPDXRef-actions-github-codeql-action-init-3.*.*"},{"relationshipType":"DEPENDS_ON","spdxElementId":"SPDXRef-com.github.tweag-dev-sec-ops-workshop","relatedSpdxElement":"SPDXRef-actions-trufflesecurity-trufflehog-main"}]} + +``` + +You can open your file in an IDE to see the whole JSON object. + +This file contains a list of the dependencies in SPDX format. You can read more about this here: + +https://spdx.dev/ + +This open standard for SBOMs contains information on: + +1. Name + +2. Version + +3. Components + +4. Licenses + +5. Copyrights + +6. Security references + + +SBOMs can be ingested into a variety of tools to demonstrate that the composition of your application is secure. For example, it can demonstrate to a third party that vulnerable dependencies have been upgraded. + +You can find tools for working with SPDX format SBOMs at the spdx.org website https://tools.spdx.org/app/ + +Now you know how to generate an SBOM, you've reached the end of this module! + + +## Wrap-up + +Congratulations you have completed Part 2 of this workshop. + +During this 4 hour session we have walked through many techniques, but we could only scratch the surface. + +Armed with the content in this workshop you can now dig in further to everything from SAST to SBOMs. + +Good luck on your DevSecOps journey. diff --git a/part2/VulnerableApp/WebContent/WEB-INF/web.xml b/part2/VulnerableApp/WebContent/WEB-INF/web.xml new file mode 100644 index 0000000..dfb6126 --- /dev/null +++ b/part2/VulnerableApp/WebContent/WEB-INF/web.xml @@ -0,0 +1,16 @@ + + + + VulnerableApp + VulnerableApp + + + VulnerableApp + /VulnerableApp + + + diff --git a/part2/VulnerableApp/pom.xml b/part2/VulnerableApp/pom.xml new file mode 100644 index 0000000..b5307d9 --- /dev/null +++ b/part2/VulnerableApp/pom.xml @@ -0,0 +1,47 @@ + + 4.0.0 + + com.yourcompany + VulnerableAppProject + 1.0-SNAPSHOT + war + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + + + org.apache.logging.log4j + log4j-core + 2.14.1 + + + + + org.apache.logging.log4j + log4j-api + 2.14.1 + + + + VulnerableAppProject + + + maven-war-plugin + 2.6 + + false + + + + + + diff --git a/part2/VulnerableApp/src/VulnerableApp.java b/part2/VulnerableApp/src/VulnerableApp.java new file mode 100644 index 0000000..807f975 --- /dev/null +++ b/part2/VulnerableApp/src/VulnerableApp.java @@ -0,0 +1,52 @@ +import java.io.*; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.Statement; +import javax.servlet.*; +import javax.servlet.http.*; + +public class VulnerableApp extends HttpServlet { + + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + // Vulnerability 1: SQL Injection + try { + String user = request.getParameter("user"); + Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/test?user=sqluser&password=sqlpassword"); + Statement stmt = conn.createStatement(); + // Unsafe query construction + ResultSet rs = stmt.executeQuery("SELECT * FROM users WHERE username = '" + user + "'"); + while (rs.next()) { + response.getWriter().println("User found: " + rs.getString("username")); + } + } catch (Exception e) { + e.printStackTrace(); + } + + // Vulnerability 2: Command Injection + try { + String data = request.getParameter("data"); + // Unsafe command execution + Runtime.getRuntime().exec("echo " + data); + } catch (IOException e) { + e.printStackTrace(); + } + + // Vulnerability 3: Path Traversal + try { + String filePath = request.getParameter("filePath"); + // Unsafe file access + FileInputStream fis = new FileInputStream("/var/www/data/" + filePath); + int ch; + PrintWriter pw = response.getWriter(); + while((ch = fis.read()) != -1) { + pw.print((char)ch); + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/part2/VulnerableAppTwo/keys/rsaexample.pem b/part2/VulnerableAppTwo/keys/rsaexample.pem new file mode 100644 index 0000000..523c04d --- /dev/null +++ b/part2/VulnerableAppTwo/keys/rsaexample.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDyQTJBfpP/OHBq +ITPfmaPHzfu7XU1TGAPEnoQJA6hZ1OEdcYe+OidET9bX0kfrEQB6vNQ/9F8yCjiK +d9qPcp8V/hyoWm1jDmjgykdBoIm7ja4lVLx4o0bVpWz3BS9CnwU/3kcdyXadt9kr ++eMQz9UP5qWUVc7fTStpsu7Hm8UezNH5NQqsCXUz69rWXwOu7egDoHefdmUVhX41 +CdlUeGoOwOxXskU/OuwhDVKttPMqdMrX7kfQnWUFyDJ7zaDtt3z5nd5vryLB/xKo +5pyIjrt/gy14yWlY+pEJ55kSxh4QwO4wUGsmbYhKU2dYNOPw89BQLPpEuzUTRdft +BXgy6zjBAgMBAAECggEAIVpmj+vcdnQPzhzaJnvht72dXfN/lOQmiKiGZzNQt2V+ +xO3/kWoyQ852NuqlqjCCD2P2GQQNIzeTB0VvGvbd/kopKeihTNUMDX7sBpYSwHbG +Ni+Pb1CTjRCkivH0yshYEa4JvokhQp+wT8SsxYDHxdOsklqqC8Z1Jq1TALpqjk3C +O+acqcsC599byOxYXN8LgxM7+rTzN6ccH/8uoXB+5yWFRDINC07ILBITImiKYGEN +QDYxlO3PKlIwGQFQXRrHnBPfgWLDhrK3jslfgE7yIaH8VRVDbv7JOkcnIyNFQ5Da +EQ1NuIiFklFD/bZnkpkpmcKzCO7Gj1leMKfGvwSnLQKBgQD6VP8zez0pFz1yN7mV +Kasyj2UdvvAQNPt5unYCawAMTY3cobob2iccDz1B1RD6wWK4YfhtYLINjIe8Sn01 +eolOPk3pEfJma5Jt5kGzWKOd7It5SUCs1UyWZfM1DIiyfPSGjHM3WkNSXc3ts71X +Twcl4EVRE3cGByH9fm2i06WDgwKBgQD3vWFuqCsC6m1VSll40Dxtf9fZYdiVfcRi +h11Rt2sim/3otRv11TVOcT+7YFMIBGxVcIAWU62aB8+O0GJImOk37aFl0z8FqnvJ +dZaEpWTY10FqRltMWk6dWgjy1yjITS1rPv3HnrTGteG0Hh1YzAHwZ44YtGDh2AXZ +S+Up+6zrawKBgQCDMBIBv78Ajr5T4iIuqoSeXYmHOi4CwFFdrLr1b2+6AtaqXlLz +D7NZQB9BJdDdKIV8zVLstzT4ZsInif3uDcZxK7OWxiH7TLqTP40E2Rn9xB4ftKTh +LnMRimIXVfc5WsSm0mn7AyGuw5wMyxoZ7D95uPt6jrHchdZpS11XbIUb0wKBgQCO +RgdfalqRKRozAijR9hzN8b5/S+77IygWQZD5LfHsBVPTQbdV/eTIMMeeD1p/3zJr ++tjEebfYHqY3aTsYYCCHiwPGm4O0+ExwzQPtF6ML2Mrrgo5KEg7V1PAQrjnwlkoA +LkPGUUGWYLvHGghWh4qRipcTXvvIl6v8N9bavnt3EwKBgHBN0KTvJBs/q9Dk9sGL +xWFU6AmfSNqgewn+jabpbr4KW3QB6ulaLvxx/4CIBz0zbr3npeLHZa0LCguilu1Y +1ZYPMaEgjkWYf600uG7zcb4ahAon86o+TKdftW3gGwfKNJs/aWQ1psfF9HRGg5AO +ZP97k2h24Qh/6Y3DkO6Cy74B +-----END PRIVATE KEY----- diff --git a/part2/VulnerableAppTwo/package.json b/part2/VulnerableAppTwo/package.json new file mode 100644 index 0000000..1f1023c --- /dev/null +++ b/part2/VulnerableAppTwo/package.json @@ -0,0 +1,20 @@ +{ + "name": "vulnerable-node-app", + "version": "1.0.0", + "description": "A Node.js application with intentionally vulnerable dependencies for demonstration purposes.", + "main": "index.js", + "scripts": { + "start": "node index.js" + }, + "dependencies": { + "express": "4.16.0", // Known to have vulnerabilities in this version + "lodash": "4.17.10", // Vulnerable version + "marked": "0.3.6", // Vulnerable version + "mongoose": "5.0.16", // Known vulnerabilities in this version + "request": "2.81.0" // Deprecated and has known vulnerabilities + }, + "devDependencies": {}, + "author": "BSides Tampa Workshop", + "license": "MIT" +} + diff --git a/part2/VulnerableAppTwo/src/VulnerableAppTwo.js b/part2/VulnerableAppTwo/src/VulnerableAppTwo.js new file mode 100644 index 0000000..ef52d4f --- /dev/null +++ b/part2/VulnerableAppTwo/src/VulnerableAppTwo.js @@ -0,0 +1,52 @@ +const express = require('express'); +const mongoose = require('mongoose'); +const marked = require('marked'); +const _ = require('lodash'); +const bodyParser = require('body-parser'); + +const app = express(); +const port = 3000; + +// Middleware +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: true })); + +// Vulnerable MongoDB connection setup +mongoose.connect('mongodb://localhost:27017/vulnerableApp', { useNewUrlParser: true, useUnifiedTopology: true }); +const UserSchema = new mongoose.Schema({ + username: String, + password: String +}); +const User = mongoose.model('User', UserSchema); + +// Route: Unsafe Deserialization (using lodash) +app.post('/api/submit', (req, res) => { + const userData = _.cloneDeep(req.body); + console.log(userData); + res.send('Data received'); +}); + +// Route: SQL (NoSQL) Injection +app.post('/api/login', async (req, res) => { + const { username, password } = req.body; + // Unsafe query + const user = await User.findOne({ username: username, password: password }); + if (user) { + res.send('Login successful'); + } else { + res.send('Login failed'); + } +}); + +// Route: Stored XSS +app.post('/api/comment', (req, res) => { + const { comment } = req.body; + // Vulnerable to XSS, as marked doesn't sanitize input by default + const htmlComment = marked(comment); + res.send(htmlComment); +}); + +app.listen(port, () => { + console.log(`Vulnerable app listening at http://localhost:${port}`); +}); + diff --git a/part2/img/codeqlexample.png b/part2/img/codeqlexample.png new file mode 100644 index 0000000..44c93e4 Binary files /dev/null and b/part2/img/codeqlexample.png differ diff --git a/part2/img/reposecret.png b/part2/img/reposecret.png new file mode 100644 index 0000000..b4d434f Binary files /dev/null and b/part2/img/reposecret.png differ diff --git a/part2/img/sbom.png b/part2/img/sbom.png new file mode 100644 index 0000000..8ad72bf Binary files /dev/null and b/part2/img/sbom.png differ diff --git a/part2/img/secretsconfig.png b/part2/img/secretsconfig.png new file mode 100644 index 0000000..3007031 Binary files /dev/null and b/part2/img/secretsconfig.png differ diff --git a/part2/img/secretsregex.png b/part2/img/secretsregex.png new file mode 100644 index 0000000..a1739eb Binary files /dev/null and b/part2/img/secretsregex.png differ