Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 122 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,19 @@ This tutorial with use CodeQL Analysis with Code Scanning in order to search for
## Instructions

<details>
<summary>Create repository using the template</summary>
<summary>Create repository fork</summary>
<p>

Begin by [creating a new repository from this template](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-repository-from-a-template).
Begin by [creating a new repository from a fork (public)](https://docs.github.com/en/get-started/quickstart/fork-a-repo) or [cloning the repository](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository).

<img src="images/00-repo-fork.png" width="70%"/>

Where creating the template repository make sure to do the following:
Where creating the forked repository, make sure to

1. Create a name for your demo
2. Select `Include all branches`
3. Create the repository from the template

<img src="images/00-repo-template.png" width="70%"/>
1. Select the correct org / user account
2. Create a name for your new repository
3. Disable main branch only cloning
4. Create the repository from the template

</p>
</details>
Expand All @@ -50,21 +49,23 @@ Click `Set up code scanning`.

#### Setup Workflow

Click the `Setup this workflow` button by CodeQL Analysis.
Click the `Setup` dropdown and select the Default CodeQL Analysis.

<img src="images/02-repo-security-setup-codeql-workflow.png" width="70%"/>
![image](https://github.com/user-attachments/assets/294a1d2a-b58a-4874-bced-c22a76fe315a)

This will create a GitHub Actions Workflow file with CodeQL already set up. Since Java is a compiled language you will need to setup the build in later steps. See the [documentation](https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/running-codeql-code-scanning-in-your-ci-system) if you would like to configure CodeQL Analysis with a 3rd party CI system instead of using GitHub Actions.
This will trigger a CodeQL Scan without needing a workflow file. Since Java is a compiled language the file will use our out-of-the-box [Autobuild action](https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages) but if your application requires more customizable compilation steps, you can switch to the advanced setup and create a workflow file where you can input your desired steps. See the [documentation](https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/running-codeql-code-scanning-in-your-ci-system) if you would like to configure CodeQL Analysis with a 3rd party CI system instead of using GitHub Actions.
</p>
</details>

<details>

<summary>Actions Workflow file</summary>
<summary>Actions Workflow file (No need to do anything!) </summary>
<p>

#### Actions Workflow

As we're going with the Default Setup, this file is not necessary but in case you're curious, here how it looks like:

The Actions Workflow file contains a number of different sections including:
1. Checking out the repository
2. Initializing the CodeQL Action
Expand All @@ -84,7 +85,12 @@ Click `Start Commit` -> `Commit this file` to commit the changes to _main_ branc

#### Workflow triggers

There are a [number of events](https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows) that can trigger a GitHub Actions workflow. In this example, the workflow will be triggered on
There are a [number of events](https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows) that can trigger a GitHub Actions workflow.

In this example, with the default setup the triggers will be:
![image](https://github.com/user-attachments/assets/6bcc8f35-8f04-45e3-aa1f-82fce86d60ae)

Whereas with the workflow, it will be triggered on:

<img src="images/04-actions-sample-events.png" width="50%"/>

Expand Down Expand Up @@ -165,9 +171,27 @@ Click `show paths` in order to see the dataflow path that resulted in this alert

<details>
<p>
<summary>Fix the Security Alert (with Copilot)</summary>
<p>
In order to fix this specific alert, we will need to ensure parameters used in the SQL query is validated and sanitized. We will solve this with the power of Copilot!
</p>
Open the file [`IndexController.java`](./src/main/java/com/github/hackathon/advancedsecurityjava/Controllers/IndexController.java) in the `Controllers` folder and select line 40. Once highlighted, select `Shift` on your keyboard and click line 53. Finally, click on the Copilot icon that appears to the side of the highlighted code.

<summary>Fix the Security Alert</summary>
![image](https://github.com/user-attachments/assets/2251deb3-2498-4f2f-a355-e35b37de58a4)

Ask Copilot the following prompt or feel free to try with a prompt of your own!
- English: Rewrite this method to prevent a SQL injection
- Spanish: Reescribe este método para prevenir SQL injection

Integrate the suggested code in your Index Controller. Make sure to click [Edit](https://docs.github.com/en/free-pro-team@latest/github/managing-files-in-a-repository/editing-files-in-your-repository) on the file.

Click `Create a new branch for this commit and start a pull request`, name the branch `fix-sql-injection`, and create the Pull Request.

</details>
<details>
<p>
<summary>Fix the Security Alert (without Copilot)</summary>
</p>
In order to fix this specific alert, we will need to ensure parameters used in the SQL query is validated and sanitized.

Click on the `Code` tab and [Edit](https://docs.github.com/en/free-pro-team@latest/github/managing-files-in-a-repository/editing-files-in-your-repository) the file [`IndexController.java`](./src/main/java/com/github/hackathon/advancedsecurityjava/Controllers/IndexController.java) in the `Controllers` folder, replace the content with the file [`fixme`](./fixme).
Expand All @@ -176,6 +200,12 @@ Click on the `Code` tab and [Edit](https://docs.github.com/en/free-pro-team@late

Click `Create a new branch for this commit and start a pull request`, name the branch `fix-sql-injection`, and create the Pull Request.

</details>
<details>
<p>
<summary>Re-Scan your code after new changes</summary>
</p>

#### Pull Request Status Check

In the Pull Request, you will notice that the CodeQL Analysis has started as a status check. Wait until it completes.
Expand Down Expand Up @@ -210,7 +240,85 @@ Click on the security alert and notice that it details when the fix was made, by

</p>
</details>

<details>
<summary>Prevent new Alerts in a Pull Request</summary>
<p>

#### Create Pull Request from new feature Branch

Now that we have setup CodeQL Analysis and have fix a security alert, we can try to introduce an alert into a Pull Request.

Create a new Pull Request with the base branch as your `main` branch and the compare branch as the `new-feature` branch.

<img src="images/17-create-pull-request.png" width="70%"/>

Make sure that the base branch is set to your own repositories `main` branch versus the original repository's `main` branch.


#### Pull Request Status Check

Once the Pull Request has been created, you will notice that the CodeQL Analysis has started as a status check. Wait until it completes.

After the Workflow has completed, the `Code Scanning Results / CodeQL` status check will have failed.
Notice that Code Scanning has detected that this Pull Request introduces a new security alert.

<img src="images/18-pr-check-failed.png" width="80%"/>


#### Alert Centric Notifications

Directly in the Pull Request, you will notice that GitHub Code Scanning bot has left a review of the Pull Request with the security alert details.
This will help developers to quickly identify security issues introduced in their Pull Requests.

<img src="images/19-pr-review.png" width="80%"/>


This also allows for collaboration between developers and security teams to discuss the security alert and how to remediate it.

<img src="images/20-pr-review-collaboration.png" width="80%"/>

#### Security Alert Details

Click on `Show more details` by the new `Code Scanning Alert` to jump to the `Security` tab and view the security alert details.

<img src="images/21-pr-show-more-details.png" width="80%"/>

Notice that the security alert was found `In pull request` and not in the `main` branch (production).


</p>
</details>
<details>
<p><summary>(Bonus) Enable Secret Scanning</summary></p>
<p>
Click on `Settings` and select `Code Security` from the menu on the left.

![image](https://github.com/user-attachments/assets/d56f94fb-5623-481f-b850-291248104304)

Find the options for Secret Scanning and Push Protection and make sure they are both Enabled. When they are it should say disabled, similar to this image:

![image](https://github.com/user-attachments/assets/23f92127-bef0-4107-91e2-00a802daff47)

</p>
</details>
<details>
<p><summary>(Bonus) Try to introduce a Secret</summary></p>
<p>

Find yourself a secret that matches any of the [supported secrets](https://docs.github.com/en/code-security/secret-scanning/introduction/supported-secret-scanning-patterns#supported-secrets) and try to commit the value to the Repo. You could commit it to any file! Refer to the previous activities to refresh how Edit and Commit a change.

If you received an error, you've done it right!!

If you didn't receive an error, this may be why:
1. The secret is not supported out-of-the-box. For secrets not in the [supported secrets](https://docs.github.com/en/code-security/secret-scanning/introduction/supported-secret-scanning-patterns#supported-secrets) list, you will need to [create a Custom Pattern](https://docs.github.com/en/enterprise-cloud@latest/code-security/secret-scanning/using-advanced-secret-scanning-and-push-protection-features/custom-patterns/defining-custom-patterns-for-secret-scanning) first.
2. The secret was already leaked and you already have an Open Alert in your Security page. Why cry over spilled milk?!
3. Check again that Push Protection is enabled on your Repo!

</p>
</details>


## Next Steps

Ready to talk about advanced security features for GitHub Enterprise? [Contact Sales](https://enterprise.github.com/contact) for more information!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

Expand All @@ -28,31 +28,41 @@ public List<Book> getBooks(@RequestParam(name = "name", required = false) String
@RequestParam(name = "read", required = false) Boolean bookread) {
List<Book> books = new ArrayList<Book>();

Statement statement = null;
PreparedStatement statement = null;
List<String> parameters = new ArrayList<>();

try {
// Init connection to DB
connection = DriverManager.getConnection(Application.connectionString);

statement = connection.createStatement();
String query = null;

if (bookname != null) {
// Filter by book name
query = "SELECT * FROM Books WHERE name LIKE '%" + bookname + "%'";
query = "SELECT * FROM Books WHERE name LIKE ?";
parameters.add("%" + bookname + "%");
} else if (bookauthor != null) {
// Filter by book author
query = "SELECT * FROM Books WHERE author LIKE '%" + bookauthor + "%'";
query = "SELECT * FROM Books WHERE author LIKE ?";
parameters.add("%" + bookauthor + "%");
} else if (bookread != null) {
// Filter by if the book has been read or not
Integer read = bookread ? 1 : 0;
query = "SELECT * FROM Books WHERE read = '" + read.toString() + "'";
query = "SELECT * FROM Books WHERE read = ?";
parameters.add(read.toString());
} else {
// All books
query = "SELECT * FROM Books";
}

ResultSet results = statement.executeQuery(query);
statement = connection.prepareStatement(query);
int index = 1;
for (String parameter : parameters) {
statement.setString(index, parameter);
index += 1;
}

ResultSet results = statement.executeQuery();

while (results.next()) {
Book book = new Book(results.getString("name"), results.getString("author"), (results.getInt("read") == 1));
Expand All @@ -76,4 +86,4 @@ public List<Book> getBooks(@RequestParam(name = "name", required = false) String
}
return books;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.github.hackathon.advancedsecurityjava.Controllers;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import com.github.hackathon.advancedsecurityjava.Application;
import com.github.hackathon.advancedsecurityjava.Models.Book;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;


@Controller
public class SearchController {

@GetMapping("/search")
@ResponseBody
public List<Book> searchBooks(@RequestParam(name = "q", required = true) String search) {
List<Book> books = new ArrayList<Book>();

Application.logger.info("Search query: {}", search);

String query = "SELECT * FROM Books WHERE name LIKE '%" + search + "%' OR author LIKE '%" + search + "%'";
try(Connection connection = DriverManager.getConnection(Application.connectionString))
{
try (Statement statement = connection.createStatement()) {
ResultSet results = statement.executeQuery(query);

Check failure

Code scanning / CodeQL

Query built from user-controlled sources

This query depends on a [user-provided value](1).

while (results.next()) {
Book book = new Book(results.getString("name"), results.getString("author"), (results.getInt("read") == 1));

books.add(book);
}
} catch (SQLException error) {
error.printStackTrace();
}
} catch (SQLException error) {
error.printStackTrace();
}

return books;
}
}