diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index f56a57afa..591ed9e81 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -22,7 +22,8 @@ jobs: - name: Checkout CredData uses: actions/checkout@v3 with: - repository: Samsung/CredData + repository: babenek/CredData + ref: jwt - name: Cache data id: cache-data @@ -62,7 +63,8 @@ jobs: - name: Checkout CredData uses: actions/checkout@v3 with: - repository: Samsung/CredData + repository: babenek/CredData + ref: jwt - name: Cache data id: cache-data @@ -148,187 +150,3 @@ jobs: # update cicd/benchmark.txt with uploaded artifact if a difference is found run: | diff CredSweeper/cicd/benchmark.txt benchmark.txt - -# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # - - performance_benchmark: - # put the benchmark in single job to keep constant environment during test - needs: [download_data] - - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - python-version: ["3.8", "3.9", "3.10", "3.11"] - - steps: - - - name: Checkout CredData - uses: actions/checkout@v3 - with: - repository: Samsung/CredData - - - name: Cache data - id: cache-data - uses: actions/cache@v3 - with: - path: data - key: cred-data-${{ hashFiles('snapshot.yaml') }} - - - name: Failure in case when cache missed - if: steps.cache-data.outputs.cache-hit != 'true' - run: exit 1 - - - name: Exclude very huge data - if: steps.cache-data.outputs.cache-hit == 'true' - run: rm -rf data/8* data/7* data/a* data/2* data/0* data/f* data/b* data/d* - - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 - with: - python-version: ${{ matrix.python-version }} - - - name: Add synthetic huge data - if: steps.cache-data.outputs.cache-hit == 'true' - run: python -c "for n in range(7654321):print(f'{n:08x}')" >data/test.text - - - name: Update PIP - run: python -m pip install --upgrade pip - - - name: Fix onnxruntime lib for released version 1.5.5 - todo remove it after new release - run: python -m pip install onnxruntime==1.15.1 - - - name: Install released CredSweeper - run: | - python -m pip install credsweeper - # check the banner - credsweeper --banner - - - name: Run performance benchmark RELEASE - run: | - START_TIME=$(date +%s) - /usr/bin/time --verbose credsweeper --log error --path data --save-json /dev/null - FINISH_TIME=$(date +%s) - RELEASE_TIME=$(( ${FINISH_TIME} - ${START_TIME} )) - if [ 0 -lt ${RELEASE_TIME} ]; then - echo Elapsed $(date -ud "@${RELEASE_TIME}" +"%H:%M:%S") - else - echo "Wrong result '${RELEASE_TIME}'" - exit 1 - fi - echo "RELEASE_TIME=${RELEASE_TIME}" >> $GITHUB_ENV - - - name: Uninstall released CredSweeper - run: | - python -m pip uninstall -y credsweeper - - - name: Checkout base CredSweeper - uses: actions/checkout@v3 - with: - ref: ${{ github.event.pull_request.base.sha }} - path: temp/CredSweeper.base - - - name: Install base CredSweeper - run: | - python -m pip install temp/CredSweeper.base - # check the banner - credsweeper --banner - - - name: Run performance benchmark BASE - run: | - START_TIME=$(date +%s) - /usr/bin/time --verbose credsweeper --log error --path data --save-json /dev/null - FINISH_TIME=$(date +%s) - BASE_TIME=$(( ${FINISH_TIME} - ${START_TIME} )) - if [ 0 -lt ${BASE_TIME} ]; then - echo Elapsed $(date -ud "@${BASE_TIME}" +"%H:%M:%S") - else - echo "Wrong result '${BASE_TIME}'" - exit 1 - fi - echo "BASE_TIME=${BASE_TIME}" >> $GITHUB_ENV - - - name: Checkout current CredSweeper - uses: actions/checkout@v3 - with: - ref: ${{ github.event.pull_request.head.sha }} - path: temp/CredSweeper.head - - - name: Install current CredSweeper - run: | - python -m pip install temp/CredSweeper.head - # check the banner - credsweeper --banner - - - name: Run performance benchmark CURRENT - run: | - START_TIME=$(date +%s) - /usr/bin/time --verbose credsweeper --log error --path data --save-json /dev/null - FINISH_TIME=$(date +%s) - HEAD_TIME=$(( ${FINISH_TIME} - ${START_TIME} )) - if [ 0 -lt ${HEAD_TIME} ]; then - echo Elapsed $(date -ud "@${HEAD_TIME}" +"%H:%M:%S") - else - echo "Wrong result '${HEAD_TIME}'" - exit 1 - fi - echo "HEAD_TIME=${HEAD_TIME}" >> $GITHUB_ENV - - - name: Compare results - run: | - exit_code=0 - LOW_DELTA=10 - THRESHOLD=250 - - # RELEASE - if [ ${RELEASE_TIME} -le ${HEAD_TIME} ]; then - d=$(( 1000 * ( ${HEAD_TIME} - ${RELEASE_TIME} ) / ${RELEASE_TIME} )) - echo "RELEASE_TIME (sec) = ${RELEASE_TIME}, current (sec) = ${HEAD_TIME}. Diff (% * 10): ${d}" - if [ $LOW_DELTA -ge ${d} ]; then - echo "Almost the same." - elif [ $THRESHOLD -lt ${d} ]; then - echo "Significantly Slowdown." - exit_code=1 - else - echo "Slowdown." - fi - else - d=$(( 1000 * ( ${RELEASE_TIME} - ${HEAD_TIME} ) / ${RELEASE_TIME} )) - echo "RELEASE_TIME (sec) = ${RELEASE_TIME}, current (sec) = ${HEAD_TIME}. Diff (% * 10): ${d}" - if [ $LOW_DELTA -ge ${d} ]; then - echo "Almost the same." - elif [ $THRESHOLD -lt ${d} ]; then - echo "Significantly speed-up." - else - echo "Speed-up." - fi - fi - - # BASE - if [ ${BASE_TIME} -le ${HEAD_TIME} ]; then - d=$(( 1000 * ( ${HEAD_TIME} - ${BASE_TIME} ) / ${BASE_TIME} )) - echo "BASE_TIME (sec) = ${BASE_TIME}, current (sec) = ${HEAD_TIME}. Diff (% * 10): ${d}" - if [ $LOW_DELTA -ge ${d} ]; then - echo "Almost the same." - elif [ $THRESHOLD -lt ${d} ]; then - echo "Significantly Slowdown." - exit_code=1 - else - echo "Slowdown." - fi - else - d=$(( 1000 * ( ${BASE_TIME} - ${HEAD_TIME} ) / ${BASE_TIME} )) - echo "BASE_TIME (sec) = ${BASE_TIME}, current (sec) = ${HEAD_TIME}. Diff (% * 10): ${d}" - if [ $LOW_DELTA -ge ${d} ]; then - echo "Almost the same." - elif [ $THRESHOLD -lt ${d} ]; then - echo "Significantly speed-up." - else - echo "Speed-up." - fi - fi - - exit ${exit_code} - -# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # - diff --git a/credsweeper/filters/__init__.py b/credsweeper/filters/__init__.py index f5b7f5896..94fe1a1e1 100644 --- a/credsweeper/filters/__init__.py +++ b/credsweeper/filters/__init__.py @@ -20,6 +20,7 @@ from credsweeper.filters.value_grafana_check import ValueGrafanaCheck from credsweeper.filters.value_ip_check import ValueIPCheck from credsweeper.filters.value_json_web_token_check import ValueJsonWebTokenCheck +from credsweeper.filters.value_jwt_lite_check import ValueJWTLiteCheck from credsweeper.filters.value_last_word_check import ValueLastWordCheck from credsweeper.filters.value_length_check import ValueLengthCheck from credsweeper.filters.value_method_check import ValueMethodCheck diff --git a/credsweeper/filters/value_base64_data_check.py b/credsweeper/filters/value_base64_data_check.py index 736c86009..bd3295222 100644 --- a/credsweeper/filters/value_base64_data_check.py +++ b/credsweeper/filters/value_base64_data_check.py @@ -1,4 +1,3 @@ -import base64 import contextlib import string @@ -40,14 +39,6 @@ def run(self, line_data: LineData, target: AnalysisTarget) -> bool: return True # check whether decoded bytes have enough entropy with contextlib.suppress(Exception): - value_len = len(value) - if 0x3 & value_len: - # Bitbucket client id is 18 chars length - pad_len = 4 - (0x3 & value_len) - value = value + ''.join(['='] * pad_len) - if '-' in value or '_' in value: - decoded = base64.urlsafe_b64decode(value) - else: - decoded = base64.standard_b64decode(value) + decoded = Util.decode_base64(value, padding_safe=True, urlsafe_detect=True) return Util.is_ascii_entropy_validate(decoded) return True diff --git a/credsweeper/filters/value_grafana_check.py b/credsweeper/filters/value_grafana_check.py index c9e215fca..3bd583555 100644 --- a/credsweeper/filters/value_grafana_check.py +++ b/credsweeper/filters/value_grafana_check.py @@ -1,4 +1,3 @@ -import base64 import contextlib import json @@ -6,6 +5,7 @@ from credsweeper.credentials import LineData from credsweeper.file_handler.analysis_target import AnalysisTarget from credsweeper.filters import Filter +from credsweeper.utils import Util class ValueGrafanaCheck(Filter): @@ -30,11 +30,11 @@ def run(self, line_data: LineData, target: AnalysisTarget) -> bool: with contextlib.suppress(Exception): if line_data.value.startswith("glc_"): # Grafana Access Policy Token - decoded = base64.b64decode(line_data.value[4:]) + decoded = Util.decode_base64(line_data.value[4:], padding_safe=True, urlsafe_detect=True) keys = ["o", "n", "k", "m"] else: # Grafana Provisioned API Key - decoded = base64.b64decode(line_data.value) + decoded = Util.decode_base64(line_data.value, padding_safe=True, urlsafe_detect=True) keys = ["n", "k", "id"] if payload := json.loads(decoded): for key in keys: diff --git a/credsweeper/filters/value_json_web_token_check.py b/credsweeper/filters/value_json_web_token_check.py index 0649c694c..47d4e3e51 100644 --- a/credsweeper/filters/value_json_web_token_check.py +++ b/credsweeper/filters/value_json_web_token_check.py @@ -1,4 +1,3 @@ -import base64 import contextlib import json @@ -6,6 +5,7 @@ from credsweeper.credentials import LineData from credsweeper.file_handler.analysis_target import AnalysisTarget from credsweeper.filters import Filter +from credsweeper.utils import Util class ValueJsonWebTokenCheck(Filter): @@ -33,9 +33,13 @@ def run(self, line_data: LineData, target: AnalysisTarget) -> bool: return True with contextlib.suppress(Exception): delimiter_pos = line_data.value.find(".") - # jwt token. '.' must be always in given data, according regex in rule - value = line_data.value[:delimiter_pos] - decoded = base64.b64decode(value) + # JWT token. '.' MAY be always in given data + if 0 <= delimiter_pos: + value = line_data.value[:delimiter_pos] + else: + value = line_data.value + # https://www.rfc-editor.org/rfc/rfc7515.txt - padding is optional + decoded = Util.decode_base64(value, padding_safe=True, urlsafe_detect=True) if header := json.loads(decoded): if "alg" in header or "typ" in header: return False diff --git a/credsweeper/filters/value_jwt_lite_check.py b/credsweeper/filters/value_jwt_lite_check.py new file mode 100644 index 000000000..c45771cdc --- /dev/null +++ b/credsweeper/filters/value_jwt_lite_check.py @@ -0,0 +1,45 @@ +import contextlib +import string + +from credsweeper.common.constants import LATIN_1, ASCII +from credsweeper.config import Config +from credsweeper.credentials import LineData +from credsweeper.file_handler.analysis_target import AnalysisTarget +from credsweeper.filters import Filter +from credsweeper.utils import Util + + +class ValueJWTLiteCheck(Filter): + """ + Lite check for Json Web Token in base64 encoding. + Checks first 12 decoded bytes - only ascii symbols allowed. + It requires only 16 symbols in base64 encoding. + eyJ0eXAiOm51bGx9 -> {"typ":null} + """ + + def __init__(self, config: Config = None) -> None: + self.printable = set(string.printable) + + def run(self, line_data: LineData, target: AnalysisTarget) -> bool: + """Run filter checks on received token which might be structured. + + Args: + line_data: credential candidate data + target: multiline target from which line data was obtained + + Return: + True, when need to filter candidate and False if left + + """ + if not line_data.value or 16 > len(line_data.value): + return True + with contextlib.suppress(Exception): + decoded = Util.decode_base64(line_data.value[0:16], urlsafe_detect=True) + for i in decoded.decode(ASCII): + # check that only printable symbols must be + if i not in self.printable: + break + else: + # no wrong symbols found - may be a JWT + return False + return True diff --git a/credsweeper/filters/value_structured_token_check.py b/credsweeper/filters/value_structured_token_check.py index e2ee64f56..161e555b3 100644 --- a/credsweeper/filters/value_structured_token_check.py +++ b/credsweeper/filters/value_structured_token_check.py @@ -1,4 +1,3 @@ -import base64 import binascii import contextlib @@ -55,7 +54,7 @@ def check_crc32_struct(value: str) -> bool: @staticmethod def check_atlassian_struct(value: str) -> bool: """Returns False if value is valid for atlassian structure 'integer:bytes'""" - decoded = base64.b64decode(value) + decoded = Util.decode_base64(value, padding_safe=True, urlsafe_detect=True) delimiter_pos = decoded.find(b':') # there is limit for big integer value: math.log10(1<<64) = 19.265919722494797 if 0 < delimiter_pos <= 20: diff --git a/credsweeper/rules/config.yaml b/credsweeper/rules/config.yaml index 6a81b1832..2e11426ba 100644 --- a/credsweeper/rules/config.yaml +++ b/credsweeper/rules/config.yaml @@ -265,11 +265,12 @@ min_line_len: 105 - name: JSON Web Token - severity: medium + severity: critical type: pattern values: - - (^|[^.0-9A-Za-z_/+-])(?PeyJ[A-Za-z0-9=_-]{13,}(\.[A-Za-z0-9-_.+\/=]+)?) - filter_type: GeneralPattern + - (^|[^.0-9A-Za-z_/+-])(?PeyJ[0-9A-Za-z=_/+-]{13,}[.0-9A-Za-z_/+-]*)([^=0-9A-Za-z_/+-]|$) + filter_type: + - ValueJsonWebTokenCheck use_ml: true required_substrings: - eyJ @@ -617,7 +618,7 @@ severity: high type: pattern values: - - (^|[^.0-9A-Za-z_/+-])(?PeyJ[A-Za-z0-9_=-]{50,500}\.eyJ[A-Za-z0-9_=-]+\.[A-Za-z0-9_=-]+) + - (^|[^.0-9A-Za-z_/+-])(?PeyJ[A-Za-z0-9_=-]{50,500}\.eyJ[A-Za-z0-9_=-]+\.[A-Za-z0-9_=-]+)([^.0-9A-Za-z_-]|$) filter_type: - ValueJsonWebTokenCheck required_substrings: @@ -798,7 +799,7 @@ severity: high type: pattern values: - - (^|[^.0-9A-Za-z_/+-])(?PeyJ[a-zA-Z0-9=/-]{64,360})([^=0-9A-Za-z_/+-]|$) + - (^|[^.0-9A-Za-z_/+-])(?PeyJ[0-9A-Za-z_=-]{64,360})([^=0-9A-Za-z_/+-]|$) filter_type: - ValueGrafanaCheck min_line_len: 67 @@ -809,7 +810,7 @@ severity: high type: pattern values: - - (^|[^.0-9A-Za-z_/+-])(?Pglc_eyJ[a-zA-Z0-9=/-]{80,360})([^=0-9A-Za-z_/+-]|$) + - (^|[^.0-9A-Za-z_/+-])(?Pglc_eyJ[0-9A-Za-z_=-]{80,360})([^=0-9A-Za-z_/+-]|$) filter_type: - ValueGrafanaCheck min_line_len: 87 diff --git a/credsweeper/utils/util.py b/credsweeper/utils/util.py index 20d3fc760..33bac15fa 100644 --- a/credsweeper/utils/util.py +++ b/credsweeper/utils/util.py @@ -1,4 +1,5 @@ import ast +import base64 import json import logging import math @@ -613,3 +614,17 @@ def parse_python(source: str) -> List[Any]: src = ast.parse(source) result = Util.ast_to_dict(src) return result + + @staticmethod + def decode_base64(text: str, padding_safe: bool = False, urlsafe_detect=False) -> bytes: + """decode text to bytes with / without padding detect and urlsafe symbols""" + value = text + if padding_safe: + pad_num = 0x3 & len(value) + if pad_num: + value += '=' * (4 - pad_num) + if urlsafe_detect and '-' in value or '_' in value: + decoded = base64.urlsafe_b64decode(value) + else: + decoded = base64.standard_b64decode(value) + return decoded diff --git a/tests/__init__.py b/tests/__init__.py index f4855ce15..372e7d217 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,7 +1,7 @@ from pathlib import Path # total number of files in test samples -SAMPLES_FILES_COUNT: int = 120 +SAMPLES_FILES_COUNT: int = 121 # credentials count after scan SAMPLES_CRED_COUNT: int = 372 diff --git a/tests/data/depth_3.json b/tests/data/depth_3.json index 9c2cda88e..e2dc9e5ab 100644 --- a/tests/data/depth_3.json +++ b/tests/data/depth_3.json @@ -5783,23 +5783,23 @@ { "api_validation": "NOT_AVAILABLE", "ml_validation": "VALIDATED_KEY", - "ml_probability": 0.99868, + "ml_probability": 0.98621, "rule": "JSON Web Token", "severity": "medium", "line_data_list": [ { - "line": "$payload = 'eyJgsIZgeJhvNgFpSmlP.eyJcaaF9xCe7shE0ENPiBlEJOpS'", + "line": "$payload = \"eyJ0fXAiOm51bGx9-----.eyJcaaF9xCe7shE0ENPiBlEJOpS\"", "line_num": 1, "path": "tests/samples/json_web_token.hs", "info": "tests/samples/json_web_token.hs|RAW", - "value": "eyJgsIZgeJhvNgFpSmlP.eyJcaaF9xCe7shE0ENPiBlEJOpS", + "value": "eyJ0fXAiOm51bGx9-----.eyJcaaF9xCe7shE0ENPiBlEJOpS", "value_start": 12, - "value_end": 60, + "value_end": 61, "variable": null, "entropy_validation": { "iterator": "BASE64_CHARS", - "entropy": 4.520488802699322, - "valid": true + "entropy": 4.350364505927827, + "valid": false } } ] diff --git a/tests/data/doc.json b/tests/data/doc.json index 6e53482dc..a557d65ef 100644 --- a/tests/data/doc.json +++ b/tests/data/doc.json @@ -10385,23 +10385,23 @@ { "api_validation": "NOT_AVAILABLE", "ml_validation": "VALIDATED_KEY", - "ml_probability": 0.99868, + "ml_probability": 0.98621, "rule": "JSON Web Token", "severity": "medium", "line_data_list": [ { - "line": "$payload = 'eyJgsIZgeJhvNgFpSmlP.eyJcaaF9xCe7shE0ENPiBlEJOpS'", + "line": "$payload = \"eyJ0fXAiOm51bGx9-----.eyJcaaF9xCe7shE0ENPiBlEJOpS\"", "line_num": 1, "path": "tests/samples/json_web_token.hs", "info": "tests/samples/json_web_token.hs|RAW", - "value": "eyJgsIZgeJhvNgFpSmlP.eyJcaaF9xCe7shE0ENPiBlEJOpS", + "value": "eyJ0fXAiOm51bGx9-----.eyJcaaF9xCe7shE0ENPiBlEJOpS", "value_start": 12, - "value_end": 60, + "value_end": 61, "variable": null, "entropy_validation": { "iterator": "BASE64_CHARS", - "entropy": 4.520488802699322, - "valid": true + "entropy": 4.350364505927827, + "valid": false } } ] diff --git a/tests/data/ml_threshold_0.json b/tests/data/ml_threshold_0.json index 3b130dbda..d5c33cf13 100644 --- a/tests/data/ml_threshold_0.json +++ b/tests/data/ml_threshold_0.json @@ -7636,18 +7636,18 @@ "severity": "medium", "line_data_list": [ { - "line": "$payload = 'eyJgsIZgeJhvNgFpSmlP.eyJcaaF9xCe7shE0ENPiBlEJOpS'", + "line": "$payload = \"eyJ0fXAiOm51bGx9-----.eyJcaaF9xCe7shE0ENPiBlEJOpS\"", "line_num": 1, "path": "tests/samples/json_web_token.hs", "info": "", - "value": "eyJgsIZgeJhvNgFpSmlP.eyJcaaF9xCe7shE0ENPiBlEJOpS", + "value": "eyJ0fXAiOm51bGx9-----.eyJcaaF9xCe7shE0ENPiBlEJOpS", "value_start": 12, - "value_end": 60, + "value_end": 61, "variable": null, "entropy_validation": { "iterator": "BASE64_CHARS", - "entropy": 4.520488802699322, - "valid": true + "entropy": 4.350364505927827, + "valid": false } } ] diff --git a/tests/data/output.json b/tests/data/output.json index 0e483ea22..4f2e2f26e 100644 --- a/tests/data/output.json +++ b/tests/data/output.json @@ -5639,23 +5639,23 @@ { "api_validation": "NOT_AVAILABLE", "ml_validation": "VALIDATED_KEY", - "ml_probability": 0.99868, + "ml_probability": 0.98621, "rule": "JSON Web Token", "severity": "medium", "line_data_list": [ { - "line": "$payload = 'eyJgsIZgeJhvNgFpSmlP.eyJcaaF9xCe7shE0ENPiBlEJOpS'", + "line": "$payload = \"eyJ0fXAiOm51bGx9-----.eyJcaaF9xCe7shE0ENPiBlEJOpS\"", "line_num": 1, "path": "tests/samples/json_web_token.hs", "info": "", - "value": "eyJgsIZgeJhvNgFpSmlP.eyJcaaF9xCe7shE0ENPiBlEJOpS", + "value": "eyJ0fXAiOm51bGx9-----.eyJcaaF9xCe7shE0ENPiBlEJOpS", "value_start": 12, - "value_end": 60, + "value_end": 61, "variable": null, "entropy_validation": { "iterator": "BASE64_CHARS", - "entropy": 4.520488802699322, - "valid": true + "entropy": 4.350364505927827, + "valid": false } } ] diff --git a/tests/filters/test_value_json_web_token_check.py b/tests/filters/test_value_json_web_token_check.py index 54e2a15fc..4b32ddf48 100644 --- a/tests/filters/test_value_json_web_token_check.py +++ b/tests/filters/test_value_json_web_token_check.py @@ -11,17 +11,20 @@ class TestValueJsonWebTokenCheck: @pytest.mark.parametrize("line", ["12345:asbdsa:28yd"]) def test_value_jwt_check_p(self, file_path: pytest.fixture, line: str) -> None: + jwt_like_line = base64.urlsafe_b64encode('{"typ":"JWT", "dummy": false}'.encode('ascii')).decode('ascii') + jwt_line_data = get_line_data(file_path, line=f"{jwt_like_line}", pattern=LINE_VALUE_PATTERN) + assert ValueJsonWebTokenCheck().run(jwt_line_data, DUMMY_ANALYSIS_TARGET) is False encoded_line = base64.b64encode(line.encode('ascii')).decode('ascii') - jwt_like_line = base64.b64encode('{"typ":"JWT", "dummy": false}'.encode('ascii')).decode('ascii') jwt_line_data = get_line_data(file_path, line=f"{jwt_like_line}.{encoded_line}", pattern=LINE_VALUE_PATTERN) assert ValueJsonWebTokenCheck().run(jwt_line_data, DUMMY_ANALYSIS_TARGET) is False - # partially line + assert '=' in jwt_like_line # just demonstrate that encoded header contains padding symbol + jwt_like_line = jwt_like_line.replace('=', '') jwt_line_data = get_line_data(file_path, line=f"{jwt_like_line}.AnyTailOfString", pattern=LINE_VALUE_PATTERN) assert ValueJsonWebTokenCheck().run(jwt_line_data, DUMMY_ANALYSIS_TARGET) is False @pytest.mark.parametrize("line", ["1234f:asbdsa:28yd"]) def test_value_jwt_check_n(self, file_path: pytest.fixture, line: str) -> None: - encoded_line = base64.b64encode(line.encode('ascii')).decode('ascii') + encoded_line = base64.urlsafe_b64encode(line.encode('ascii')).decode('ascii') jwt_line_data = get_line_data(file_path, line=f"eyJungle.{encoded_line}", pattern=LINE_VALUE_PATTERN) assert ValueJsonWebTokenCheck().run(jwt_line_data, DUMMY_ANALYSIS_TARGET) is True jwt_line_data = get_line_data(file_path, line="eyJungle", pattern=LINE_VALUE_PATTERN) diff --git a/tests/samples/false_jwt.eml b/tests/samples/false_jwt.eml new file mode 100644 index 000000000..b9283e83e --- /dev/null +++ b/tests/samples/false_jwt.eml @@ -0,0 +1,2 @@ +eyJAlZtHKjCmuF7VOfkYIlcd6iG7bz59JA3hELeC8hrlJfZ8z5C0j7JAEnQBTfy6rAPZmRBqU7k6 + diff --git a/tests/samples/json_web_token.hs b/tests/samples/json_web_token.hs index 76f919b6c..4ee294e37 100644 --- a/tests/samples/json_web_token.hs +++ b/tests/samples/json_web_token.hs @@ -1 +1 @@ -$payload = 'eyJgsIZgeJhvNgFpSmlP.eyJcaaF9xCe7shE0ENPiBlEJOpS' +$payload = "eyJ0fXAiOm51bGx9-----.eyJcaaF9xCe7shE0ENPiBlEJOpS"