Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds Gradle Wrapper Validation script #34

Merged
merged 3 commits into from
Nov 23, 2022

Conversation

oguzkocer
Copy link
Contributor

@oguzkocer oguzkocer commented Nov 18, 2022

This PR adds bin/validate_gradle_wrapper helper script which we can use to validate the Gradle Wrapper in our projects using Buildkite.

During the implementation of this script, I've consulted with the official Gradle Wrapper Documentation as well as the official Gradle Wrapper Validation Github Action. Here is a summary of what the script does:

  • Finds all files with the name gradle-wrapper.jar. If no such file is found, it'll fail with the following error: No gradle-wrapper.jar files found. This is because if we don't have any Gradle Wrapper files in the project, we shouldn't be calling this script. If we do and it still fails, it's possibly due to Homoglyph attack. (more on that below)
  • If there is at least one gradle-wrapper.jar file, the script will download the json from https://services.gradle.org/versions/all and make a list of urls of all the known sha256 hashes using the wrapperChecksumUrl property.
  • Since the sha256 values are not directly listed in the json file, but instead have to be downloaded from a url, we have to check each url until we find a match. We can possibly avoid this by using the Gradle wrapper version information, but that adds extra complexity and it's more error prone, so in my opinion, checking each known value is better. The good news is, since we use relatively latest Gradle versions in each project, we only end up checking a few versions.
  • If we find a match for the gradle-wrapper.jar file, we'll log that information as such: './gradle/wrapper/gradle-wrapper.jar' is validated with sha256 checksum from 'https://services.gradle.org/distributions/gradle-7.4.2-wrapper.jar.sha256'. This information allows us to always come back to a build and check how it was validated.
  • We'll validate each gradle-wrapper.jar file, which in most cases will only be one, and if each of them is validated, the script will return success return code. If any of the files fail to validate, it'll exit with an error as such: Failed to validate './gradle/wrapper/gradle-wrapper.jar'.

Combining with Official Github Action

We initially wanted to use the Official Github Action, but it becomes a bit messy to use that as a prerequisite for our Buildkite actions. So, @jkmassel and I had a discussion about using our own script as a prerequisite, but also adding the Github Action as an extra piece of security. That means, if there is a validation error that our script misses, we'll at least know about it and address the issue in our script. This makes our script more future-proof and gives extra coverage for Homoglyph attacks.


Homoglyph Attacks

The main difference with this script and the official Github Action is that, this script doesn't cover all cases of Homoglyph attacks. The official Github Action will unhomoglyph each file and then if a file's name corresponds to gradle-wrapper.jar, it'll validate it.

On the contrary, since this script only looks for gradle-wrapper.jar file, if the file is a homoglyphed version, it'll not find it. That means - in most cases, it'll exit with a failure because it didn't find any gradle-wrapper.jar files. However, there is still a case this script doesn't cover and that is, if the project contains both a valid gradle-wrapper.jar file as well as a homoglyphed one, it'll return a false positive validation.

I looked into adding the same Homoglyph file name validation to the bash script, but I think it's a bit tricky and messy to do it in bash. I also thought that gradle-wrapper.jar file is probably not the only file that can be used to attack. So, in my opinion, if this is something we are worried about, we should add a more generic check to our repositories where we block any Homoglyphed file names using a list of names we keep in a central location. If we go down that route, we can use the unhomoglyph library to avoid another re-write of something that already exists.

Specifically for Gradle Wrapper validation; since we are also adding the Github Action, I don't think we should worry about it. We are already handling the Gradle upgrades ourselves. Once we start using this script as well as the Github Action, I think we will have more than enough coverage.


To Test

  • You can see this script in action in Gradle Wrapper Validation wordpress-mobile/WordPress-Android#17480.
  • If you want to test the script locally, you can call it directly from any directory and it'll validate every gradle-wrapper.jar file within it.
  • If you want to simulate a homoglyph attack coverage, you can download the gradle-wrapper.jar file from this PR, put it in a temporary directory and run this script which should fail with No gradle-wrapper.jar files found..

@oguzkocer oguzkocer force-pushed the add/validate_gradle_wrapper_script branch from c0616cf to 5082bba Compare November 18, 2022 04:50
@oguzkocer oguzkocer marked this pull request as ready for review November 22, 2022 04:22
@oguzkocer oguzkocer requested a review from a team November 22, 2022 04:23
@ParaskP7 ParaskP7 self-assigned this Nov 23, 2022
Copy link

@ParaskP7 ParaskP7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👋 @oguzkocer !

Great job on creating our own Gradle Wrapper Validation script to be run on Buildkite, also, kudos on the PR description and test instructions, very helpful! 😍 💯 🥇

I have reviewed and tested this PR as per the instructions, everything LGTM! 👍

  • You can see this script in action with this WPAndroid PR. ✅
  • If you want to test the script locally. ✅
  • If you want to simulate a homoglyph attack coverage with this PR. ✅
  • If you want to simulate a tampered gradle-wrapper.jar (see below). ⚠️

The only use-case I didn't verify in my test is the Failed to validate '$wrapper_file' as I didn't know were to find such a tampered gradle-wrapper.jar that doesn't match the official sha256. Let me know if you know how to test that. 🙏

FYI: During my review and testing I added echo everywhere to understand exactly how this script works, just in case I am missing something vital. As I am not the best script reviewer, I didn't want to take any chance here... 😄

Having said the above, maybe you might want to wait of someone else to review this script as well, someone with more experience on that. Thus, I am just approving this PR, but not merging yet.


Combining with Official Github Action

Love this, nice touch! ❤️

Homoglyph Attacks

I agree! 💯

@AliSoftware
Copy link
Contributor

I didn't know were to find such a tampered gradle-wrapper.jar that doesn't match the official sha256. Let me know if you know how to test that. 🙏

@ParaskP7 I'm guessing you can use any random .jar (or actually, probably any random file even) and rename it gradle-wrapper.jar, to get a file with that name but invalid checksum? e.g. echo "Fake Corrupted Wrapper" >gradle-wrapper.jar

@ParaskP7
Copy link

@ParaskP7 I'm guessing you can use any random .jar (or actually, probably any random file even) and rename it gradle-wrapper.jar, to get a file with that name but invalid checksum? e.g. echo "Fake Corrupted Wrapper" >gradle-wrapper.jar

Thanks @AliSoftware for the tip, but I actually tried that and what I got was that it didn't even go through the validate_checksum function, it just got straight to No gradle-wrapper.jar files found., any ideas what am I missing here, I am sure it is something basic, as I said, I am not a scripting except... 😅 😝 😑

Copy link
Contributor

@AliSoftware AliSoftware left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Thanks @oguzkocer for working on this 👍

I didn't test the PR (given Petros already did), so only reviewed the code, and it looks good and correct to me 👌
Only left a suggestion to use our hash_file (which already handles the file name removal from sha256 output), otherwise :shipit:

bin/validate_gradle_wrapper Outdated Show resolved Hide resolved
echo "Failed to validate '$wrapper_file'"
exit 1
else
echo "'$wrapper_file' is validated with sha256 checksum from '$validated_with_checksum_from_url'"
Copy link
Contributor

@AliSoftware AliSoftware Nov 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💄 small nit (to not make it look like an "in-progress" message but more like a "done" message):

Suggested change
echo "'$wrapper_file' is validated with sha256 checksum from '$validated_with_checksum_from_url'"
echo "'$wrapper_file' was validated with sha256 checksum from '$validated_with_checksum_from_url'"

Or (not sure what's the most correct one of the two in English?)

Suggested change
echo "'$wrapper_file' is validated with sha256 checksum from '$validated_with_checksum_from_url'"
echo "'$wrapper_file' has been validated with sha256 checksum from '$validated_with_checksum_from_url'"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An in-progress message would be is being validated and I believe, because the log is created at the time of the validation, the current tense is correct.

@oguzkocer oguzkocer enabled auto-merge (squash) November 23, 2022 23:42
@oguzkocer oguzkocer merged commit e4fbc71 into trunk Nov 23, 2022
@oguzkocer oguzkocer deleted the add/validate_gradle_wrapper_script branch November 23, 2022 23:42
@oguzkocer
Copy link
Contributor Author

Thank you both for the PR review! 🙇

@oguzkocer
Copy link
Contributor Author

oguzkocer commented Nov 24, 2022

@ParaskP7 Here is how to generate the Failed to validate '$wrapper_file' error:

Screen Shot 2022-11-23 at 7 10 18 PM

P.S: It looks like I forgot to cd into the test-gradle-wrapper folder after creating it, but I didn't have anything else related to this test in temp folder, so it shouldn't matter.

Note that you can no longer call this script directly because of the hash_file change. However, you can do it if you add the bin folder from this repository to your path. It looks something like this in fish shell:

$ fish_add_path ~/Developer/Projects/bash-cache-buildkite-plugin/bin/
$ ~/Developer/Projects/bash-cache-buildkite-plugin/bin/validate_gradle_wrapper

@ParaskP7
Copy link

👋 @oguzkocer @AliSoftware !

Thank you so much for the above, but actually, and shame on me (😊), as I was using the previously downloaded homoglyph gradle-wrapper.jar name by copy-pasting it to this tampered gradle-wrapper.jar of mine, this was what made it to not work on my side... What a noob right! 😅

I copy-pasted the gradle-wrapper.jar from WPAndroid's such JAR file and onto this tampered gradle-wrapper.jar of mine and test it again, everything worked as expected. After waiting a bit (as expected), I am indeed getting the Failed to validate './gradle-wrapper.jar' failure.

Again, apologies for the false alarm, and now, I'll go hide in the dark and cry... 😊 🙏 😭

@oguzkocer
Copy link
Contributor Author

@ParaskP7 No worries at all. Thanks again for reviewing and testing the PR! 🙇‍♂️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants