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

Akamai validator #339

Merged
merged 3 commits into from
Mar 26, 2021
Merged
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
6 changes: 6 additions & 0 deletions Src/Plugins/Security/SEC101.SecurePlaintextSecrets.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,12 @@
"ContentsRegex": "$SEC101/014.FacebookAccessToken",
"MessageArguments": { "secretKind": "Facebook access token" }
},
{
"Id": "SEC101/015",
"Name": "DoNotExposePlaintextSecrets/AkamaiKey",
"ContentsRegex": "$SEC101/015.AkamaiKey",
"MessageArguments": { "secretKind": "Akamai key" }
},
{
"Id": "SEC101/016",
"Name": "DoNotExposePlaintextSecrets/StripeApiKey",
Expand Down
123 changes: 123 additions & 0 deletions Src/Plugins/Security/SEC101_015.AkamaiKeyValidator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Cryptography;

using Microsoft.CodeAnalysis.Sarif.PatternMatcher.Plugins.Security.Utilities;
using Microsoft.CodeAnalysis.Sarif.PatternMatcher.Sdk;

namespace Microsoft.CodeAnalysis.Sarif.PatternMatcher.Plugins.Security
{
public class AkamaiKeyValidator : ValidatorBase
{
internal static AkamaiKeyValidator Instance;

static AkamaiKeyValidator()
{
Instance = new AkamaiKeyValidator();
}

public static string IsValidStatic(ref string matchedPattern,
ref Dictionary<string, string> groups,
ref string failureLevel,
ref string fingerprint,
ref string message)
{
return IsValidStatic(Instance,
ref matchedPattern,
ref groups,
ref failureLevel,
ref fingerprint,
ref message);
}

public static string IsValidDynamic(ref string fingerprint, ref string message, ref Dictionary<string, string> options)
{
return IsValidDynamic(Instance,
ref fingerprint,
ref message,
ref options);
}

protected override string IsValidStaticHelper(ref string matchedPattern,
ref Dictionary<string, string> groups,
ref string failureLevel,
ref string fingerprintText,
ref string message)
{
if (!groups.TryGetNonEmptyValue("id", out string id) ||
!groups.TryGetNonEmptyValue("key", out string key) ||
!groups.TryGetNonEmptyValue("pwd", out string pwd) ||
!groups.TryGetNonEmptyValue("host", out string host))
{
return nameof(ValidationState.NoMatch);
}

fingerprintText = new Fingerprint()
{
Id = id,
Password = pwd,
Key = key,
Host = host,
}.ToString();

return nameof(ValidationState.Unknown);
}

protected override string IsValidDynamicHelper(ref string fingerprintText, ref string message, ref Dictionary<string, string> options)
{
var fingerprint = new Fingerprint(fingerprintText, false);

string id = fingerprint.Id;
string key = fingerprint.Key;
string host = fingerprint.Host;
string pwd = fingerprint.Password;

try
{
string timestamp = $"{DateTime.UtcNow:yyyyMMddTHH:mm:ss}";
string header = $"client_token={id};access_token={key};timestamp={timestamp}+0000;nonce={Guid.NewGuid()}";
string textToSign = $"EG1-HMAC-SHA256 {header};";

// Generating signing key based on timestamp.
using var hmac = new HMACSHA256(Convert.FromBase64String(pwd));
string signingKey = Convert.ToBase64String(hmac.ComputeHash(Convert.FromBase64String(timestamp)));

// Generating signature based on textToSign and signingKey.
using var hmacSignature = new HMACSHA256(Convert.FromBase64String(signingKey));
string signature = Convert.ToBase64String(hmacSignature.ComputeHash(Convert.FromBase64String(textToSign)));

using HttpClient httpClient = CreateHttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
$"EG1-HMAC-SHA256",
$"{header};signature={signature}");

using HttpResponseMessage httpResponse = httpClient
.GetAsync($"{host}/ccu/v2/queues/default")
.GetAwaiter()
.GetResult();
switch (httpResponse.StatusCode)
{
case System.Net.HttpStatusCode.OK:
{
return nameof(ValidationState.AuthorizedError);
}

default:
{
message = CreateUnexpectedResponseCodeMessage(httpResponse.StatusCode);
return nameof(ValidationState.Unknown);
}
}
}
catch (Exception e)
{
return ReturnUnhandledException(ref message, e);
}
}
}
}
1 change: 1 addition & 0 deletions Src/Plugins/Security/Security.SharedStrings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
$SEC101/013/Putty.CryptographicPrivateKey=(?is)PuTTY-User-Key-File-2.+?Private-Lines:\s*[0-9]+\s*(?<key>.+?)Private-MAC:\s[0-9a-z]+([^0-9a-d]|$)
$SEC101/013/Pem.CryptographicPrivateKey=(?si)-{5}BEGIN (DSA|EC|OPENSSH|PGP|RSA|SSH2 ENCRYPTED)?\s*PRIVATE (KEY BLOCK|KEY)-{5}.*?(VERSION: [^\n]+\n)*\n(?<key>[^:]*?)-{5}END (DSA|EC|OPENSSH|PGP|RSA|SSH2 ENCRYPTED)?\s*PRIVATE (KEY BLOCK|KEY)-{5}
$SEC101/014.FacebookAccessToken=\b(?<refine>EAACEdEose0cBA(?i)[0-9a-z]+)
$SEC101/015.AkamaiKey=(?si)(?<host>https:\/\/[\w\-\.]+\.akamaiapis\.net).{0,150}((client_token.{0,10}\b(?<id>akab[\w\-]+).{0,50})|(access_token.{0,10}\b(?<key>akab[\w\-]+).{0,200})|((client_secret).{0,10}\b(?<pwd>[a-z0-9\/\\+]{43}=))){3}
$SEC101/016.StripeApiKey=\b(?<refine>(?<key>(?:r|s)k_(live|test)_(?i)[0-9a-z]{24,99}))([^0-9a-z]|$)
$SEC101/017.NpmAuthorToken=(?i)npm.{0,100}[^0-9a-z](?-i)(?<refine>(?<key>[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}))[^0-9A-Za-z]
$SEC101/018.TwilioCredentials=(?si)twilio.{1,50}\b(?<id>AC[0-9a-z]{32}).{1,500}?\b(?<key>[0-9a-f]{32})
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
{
"$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json",
"version": "2.1.0",
"runs": [
{
"tool": {
"driver": {
"name": "testhost",
"organization": "Microsoft Corporation",
"product": "Microsoft.TestHost",
"fullName": "testhost 15.0.0.0",
"version": "15.0.0.0",
"semanticVersion": "15.0.0",
"rules": [
{
"id": "SEC101/015",
"name": "DoNotExposePlaintextSecrets/AkamaiKey",
"fullDescription": {
"text": "Do not expose plaintext (or base64-encoded plaintext) secrets in versioned engineering content."
},
"messageStrings": {
"NotApplicable_InvalidMetadata": {
"text": "'{0}' was not evaluated for check '{1}' because the analysis is not relevant for the following reason: {2}."
},
"Default": {
"text": "'{0}' contains {1}{2}{3}{4}{5}."
}
},
"helpUri": "https://github.com/microsoft/sarif-pattern-matcher"
}
]
}
},
"invocations": [
{
"executionSuccessful": true
}
],
"results": [
{
"ruleId": "SEC101/015",
"ruleIndex": 0,
"level": "note",
"message": {
"id": "Default",
"arguments": [
"SEC101_015.AkamaiKey.ps1",
"an apparent ",
"",
"Akamai key",
"",
" (no validation occurred as it was not enabled. Pass '--dynamic-validation' on the command-line to validate this match)"
]
},
"locations": [
{
"physicalLocation": {
"artifactLocation": {
"uri": "src/Plugins/Tests.Security/TestData/SecurePlaintextSecrets/Inputs/SEC101_015.AkamaiKey.ps1",
"uriBaseId": "SRC_ROOT"
},
"region": {
"startLine": 1,
"startColumn": 1,
"endLine": 2,
"endColumn": 257,
"charOffset": 0,
"charLength": 325,
"snippet": {
"text": "https://akab-xxxxx-yyyyy.purge.akamaiapis.net/ccu/v2/queues/default\r\nEG1-HMAC-SHA256 client_token=akab-client-token-xxx-xxxxxxxxxxxxxxxx;access_token=akab-access-token-xxx-xxxxxxxxxxxxxxxx;timestamp=2021-03-25T19:18:12+0000;nonce=5c43bd4d-4dcd-4e22-b64b-efaa1a20047d;client_secret=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx="
}
}
}
}
],
"fingerprints": {
"AssetFingerprint/v1": "[host=https://akab-xxxxx-yyyyy.purge.akamaiapis.net][id=akab-client-token-xxx-xxxxxxxxxxxxxxxx]",
"ValidationFingerprint/v1": "[host=https://akab-xxxxx-yyyyy.purge.akamaiapis.net][id=akab-client-token-xxx-xxxxxxxxxxxxxxxx][key=akab-access-token-xxx-xxxxxxxxxxxxxxxx][pwd=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=]",
"ValidationFingerprintHash/v1": "79b46c768fffc5ddf91cd424c964b692ab306197f9d258c4b9421618b4e81edc"
},
"rank": 36.82546438092656
},
{
"ruleId": "SEC101/015",
"ruleIndex": 0,
"level": "note",
"message": {
"id": "Default",
"arguments": [
"SEC101_015.AkamaiKey.ps1",
"an apparent ",
"",
"Akamai key",
"",
" (no validation occurred as it was not enabled. Pass '--dynamic-validation' on the command-line to validate this match)"
]
},
"locations": [
{
"physicalLocation": {
"artifactLocation": {
"uri": "src/Plugins/Tests.Security/TestData/SecurePlaintextSecrets/Inputs/SEC101_015.AkamaiKey.ps1",
"uriBaseId": "SRC_ROOT"
},
"region": {
"startLine": 4,
"startColumn": 18,
"endLine": 7,
"endColumn": 67,
"charOffset": 346,
"charLength": 263,
"snippet": {
"text": "https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/\",\r\n \"client_token\": \"akab-client-token-xxx-xxxxxxxxxxxxxxxx\",\r\n \"access_token\": \"akab-access-token-xxx-xxxxxxxxxxxxxxxx\",\r\n \"client_secret\": \"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx="
}
}
}
}
],
"fingerprints": {
"AssetFingerprint/v1": "[host=https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net][id=akab-client-token-xxx-xxxxxxxxxxxxxxxx]",
"ValidationFingerprint/v1": "[host=https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net][id=akab-client-token-xxx-xxxxxxxxxxxxxxxx][key=akab-access-token-xxx-xxxxxxxxxxxxxxxx][pwd=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=]",
"ValidationFingerprintHash/v1": "9d08800893d0a3adf72f59dc5d759c751f4e669700a3d532e681cf815a809390"
},
"rank": 36.82546438092656
},
{
"ruleId": "SEC101/015",
"ruleIndex": 0,
"level": "note",
"message": {
"id": "Default",
"arguments": [
"SEC101_015.AkamaiKey.ps1",
"an apparent ",
"",
"Akamai key",
"",
" (no validation occurred as it was not enabled. Pass '--dynamic-validation' on the command-line to validate this match)"
]
},
"locations": [
{
"physicalLocation": {
"artifactLocation": {
"uri": "src/Plugins/Tests.Security/TestData/SecurePlaintextSecrets/Inputs/SEC101_015.AkamaiKey.ps1",
"uriBaseId": "SRC_ROOT"
},
"region": {
"startLine": 11,
"startColumn": 18,
"endLine": 14,
"endColumn": 67,
"charOffset": 708,
"charLength": 263,
"snippet": {
"text": "https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/\",\r\n \"access_token\": \"akab-access-token-xxx-xxxxxxxxxxxyyyyy\",\r\n \"client_token\": \"akab-client-token-xxx-xxxxxxxxxxxxxxxx\",\r\n \"client_secret\": \"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx="
}
}
}
}
],
"fingerprints": {
"AssetFingerprint/v1": "[host=https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net][id=akab-client-token-xxx-xxxxxxxxxxxxxxxx]",
"ValidationFingerprint/v1": "[host=https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net][id=akab-client-token-xxx-xxxxxxxxxxxxxxxx][key=akab-access-token-xxx-xxxxxxxxxxxyyyyy][pwd=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=]",
"ValidationFingerprintHash/v1": "78c70718fc60661d0384c3a8d0e18a2a286fa5cc7952328af2a4d9bde5c59493"
},
"rank": 42.76456715242463
}
],
"columnKind": "utf16CodeUnits"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
https://akab-xxxxx-yyyyy.purge.akamaiapis.net/ccu/v2/queues/default
EG1-HMAC-SHA256 client_token=akab-client-token-xxx-xxxxxxxxxxxxxxxx;access_token=akab-access-token-xxx-xxxxxxxxxxxxxxxx;timestamp=2021-03-25T19:18:12+0000;nonce=5c43bd4d-4dcd-4e22-b64b-efaa1a20047d;client_secret=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=

"base_url": "https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/",
"client_token": "akab-client-token-xxx-xxxxxxxxxxxxxxxx",
"access_token": "akab-access-token-xxx-xxxxxxxxxxxxxxxx",
"client_secret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=",

ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss

"base_url": "https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/",
"access_token": "akab-access-token-xxx-xxxxxxxxxxxyyyyy",
"client_token": "akab-client-token-xxx-xxxxxxxxxxxxxxxx",
"client_secret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=",