Add Simple Detections for some common saas (#554)
* Add detections for some SAAS services * Improve comment detection for urls with protocol specification in languages with // as the comment format * Update font awesome reference * Update tagreportgroups.json * Update test cases for multiline strings * Remove unused imports
This commit is contained in:
Родитель
4bb352a0c0
Коммит
8a78a5260c
|
@ -1,5 +1,4 @@
|
|||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Running;
|
||||
using BenchmarkDotNet.Running;
|
||||
|
||||
namespace ApplicationInspector.Benchmarks;
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ using System.IO;
|
|||
using System.Reflection;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using DotLiquid;
|
||||
using Microsoft.ApplicationInspector.CLI;
|
||||
using Microsoft.ApplicationInspector.Commands;
|
||||
using Microsoft.ApplicationInspector.RulesEngine;
|
||||
|
|
|
@ -5,7 +5,6 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using Microsoft.ApplicationInspector.Commands;
|
||||
using Microsoft.ApplicationInspector.RulesEngine;
|
||||
using Microsoft.CodeAnalysis.Sarif;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Net.Sockets;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.ApplicationInspector.Commands;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1, shrink-to-fit=no" name="viewport"/>
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet"/>
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.0/css/all.min.css" rel="stylesheet"/>
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet"/>
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.7.20/c3.css" rel="stylesheet"/>
|
||||
<link href="html/resources/css/appinspector.css" rel="stylesheet" type="text/css"/>
|
||||
|
||||
|
|
|
@ -82,6 +82,21 @@
|
|||
"searchPattern": "^CloudServices.AdvertisingNetwork.*",
|
||||
"displayName": "Advertising network",
|
||||
"detectedIcon": "fas fa-ad"
|
||||
},
|
||||
{
|
||||
"searchPattern": "^CloudServices.SalesForce$",
|
||||
"displayName": "Salesforce",
|
||||
"detectedIcon": "fa-solid fa-cloud"
|
||||
},
|
||||
{
|
||||
"searchPattern": "^CloudServices.ServiceNow$",
|
||||
"displayName": "ServiceNow",
|
||||
"detectedIcon": "fa-solid fa-bell-concierge"
|
||||
},
|
||||
{
|
||||
"searchPattern": "^CloudServices.WorkDay$",
|
||||
"displayName": "WorkDay",
|
||||
"detectedIcon": "fa-solid fa-calendar-day"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -315,12 +330,12 @@
|
|||
"detectedIcon": "far fa-file-archive"
|
||||
},
|
||||
{
|
||||
"searchPattern": "^Metric.Code.HTMLForm.Defined$",
|
||||
"searchPattern": ".Code.HTMLForm.Defined$",
|
||||
"displayName": "HTML form",
|
||||
"detectedIcon": "far fa-window-maximize"
|
||||
},
|
||||
{
|
||||
"searchPattern": "^Metric.Code.Exception.Caught$",
|
||||
"searchPattern": ".Code.Exception.Caught$",
|
||||
"displayName": "Exception caught",
|
||||
"detectedIcon": "fas fa-meteor"
|
||||
},
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
|
|
|
@ -243,15 +243,50 @@ public class TextContainer
|
|||
}
|
||||
}
|
||||
|
||||
private int GetPrefixLocation(int startOfLineIndex, int currentIndex, string prefix, bool multiline)
|
||||
{
|
||||
// Find the first potential index of the prefix
|
||||
var prefixLoc = FullContent.LastIndexOf(prefix, currentIndex, StringComparison.Ordinal);
|
||||
if (prefixLoc != -1)
|
||||
{
|
||||
// TODO: Possibly support quoted multiline comment markers
|
||||
if (multiline)
|
||||
{
|
||||
return prefixLoc;
|
||||
}
|
||||
if (prefixLoc < startOfLineIndex)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
// Check how many quote marks occur on the line before the prefix location
|
||||
// TODO: This doesn't account for multi-line strings
|
||||
var numDoubleQuotes = FullContent[startOfLineIndex..prefixLoc].Count(x => x == '"');
|
||||
var numSingleQuotes = FullContent[startOfLineIndex..prefixLoc].Count(x => x == '\'');
|
||||
|
||||
// If the number of quotes is odd, this is in a string, so not actually a comment prefix
|
||||
// It might be like var address = "http://contoso.com";
|
||||
if (numDoubleQuotes % 2 == 1 || numSingleQuotes % 2 == 1)
|
||||
{
|
||||
return GetPrefixLocation(startOfLineIndex, prefixLoc, prefix, multiline);
|
||||
}
|
||||
}
|
||||
|
||||
return prefixLoc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populates the CommentedStates Dictionary based on the index and the provided comment prefix and suffix
|
||||
/// </summary>
|
||||
/// <param name="index">The character index in FullContent</param>
|
||||
/// <param name="prefix">The comment prefix</param>
|
||||
/// <param name="suffix">The comment suffix</param>
|
||||
private void PopulateCommentedStatesInternal(int index, string prefix, string suffix)
|
||||
private void PopulateCommentedStatesInternal(int index, string prefix, string suffix, bool multiline)
|
||||
{
|
||||
var prefixLoc = FullContent.LastIndexOf(prefix, index, StringComparison.Ordinal);
|
||||
// Get the line boundary for the prefix location
|
||||
var startOfLine = GetLineBoundary(index);
|
||||
// Get the index of the prefix
|
||||
var prefixLoc = GetPrefixLocation(startOfLine.Index, index, prefix, multiline);
|
||||
|
||||
if (prefixLoc != -1)
|
||||
{
|
||||
if (!CommentedStates.ContainsKey(prefixLoc))
|
||||
|
@ -287,13 +322,13 @@ public class TextContainer
|
|||
// Populate true for the indexes of the most immediately preceding instance of the multiline comment type if found
|
||||
if (!string.IsNullOrEmpty(prefix) && !string.IsNullOrEmpty(suffix))
|
||||
{
|
||||
PopulateCommentedStatesInternal(index, prefix, suffix);
|
||||
PopulateCommentedStatesInternal(index, prefix, suffix, true);
|
||||
}
|
||||
|
||||
// Populate true for indexes of the most immediately preceding instance of the single-line comment type if found
|
||||
if (!CommentedStates.ContainsKey(index) && !string.IsNullOrEmpty(inline))
|
||||
{
|
||||
PopulateCommentedStatesInternal(index, inline, "\n");
|
||||
PopulateCommentedStatesInternal(index, inline, "\n", false);
|
||||
}
|
||||
|
||||
var i = index;
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using CommandLine;
|
||||
using Microsoft.ApplicationInspector.Commands;
|
||||
using Microsoft.ApplicationInspector.Common;
|
||||
using Microsoft.ApplicationInspector.Logging;
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.ApplicationInspector.Logging;
|
||||
using Microsoft.ApplicationInspector.RulesEngine;
|
||||
using Microsoft.CST.RecursiveExtractor;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Serilog.Events;
|
||||
|
||||
namespace AppInspector.Tests.RuleProcessor;
|
||||
|
||||
[TestClass]
|
||||
public class QuotedStringsTests
|
||||
{
|
||||
|
||||
private const string testDoubleQuotesAreCode = "var url = \"https://contoso.com\"; // contoso.com";
|
||||
private const string testSingleQuotesAreCode = "var url = 'https://contoso.com'; // contoso.com";
|
||||
private const string testSingleLineWithQuotesInComment = "// var url = 'https://contoso.com';";
|
||||
private const string testSingleLineWithDoubleQuotesInComment = "// var url = 'https://contoso.com';";
|
||||
private const string testMultiLine = @"/*
|
||||
https://contoso.com
|
||||
*/";
|
||||
private const string testMultiLineWithoutProto = @"
|
||||
/*
|
||||
contoso.com
|
||||
*/";
|
||||
private const string testMultiLineWithResultFollowingCommentEnd = @"
|
||||
/*
|
||||
contoso.com
|
||||
*/ var url = ""https://contoso.com""";
|
||||
|
||||
private static string detectContosoRule = @"
|
||||
[
|
||||
{
|
||||
""id"": ""RE000001"",
|
||||
""name"": ""Testing.Rules.Quotes"",
|
||||
""tags"": [
|
||||
""Testing.Rules.Quotes""
|
||||
],
|
||||
""severity"": ""Critical"",
|
||||
""description"": ""Find contoso.com"",
|
||||
""patterns"": [
|
||||
{
|
||||
""pattern"": ""contoso.com"",
|
||||
""type"": ""regex"",
|
||||
""confidence"": ""High"",
|
||||
""scopes"": [
|
||||
""code""
|
||||
]
|
||||
}
|
||||
],
|
||||
""_comment"": """"
|
||||
}
|
||||
]
|
||||
";
|
||||
|
||||
private readonly ILoggerFactory _loggerFactory =
|
||||
new LogOptions { ConsoleVerbosityLevel = LogEventLevel.Verbose }.GetLoggerFactory();
|
||||
|
||||
private readonly Microsoft.ApplicationInspector.RulesEngine.Languages _languages = new();
|
||||
|
||||
[DataRow(testDoubleQuotesAreCode,1)]
|
||||
[DataRow(testSingleQuotesAreCode,1)]
|
||||
[DataRow(testMultiLine,0)]
|
||||
[DataRow(testMultiLineWithoutProto,0)]
|
||||
[DataRow(testMultiLineWithResultFollowingCommentEnd,1)]
|
||||
[DataRow(testSingleLineWithQuotesInComment,0)]
|
||||
[DataRow(testSingleLineWithDoubleQuotesInComment,0)]
|
||||
[DataTestMethod]
|
||||
public void QuotedStrings(string content, int numIssues)
|
||||
{
|
||||
RuleSet rules = new(_loggerFactory);
|
||||
rules.AddString(detectContosoRule, "contosorule");
|
||||
Microsoft.ApplicationInspector.RulesEngine.RuleProcessor ruleProcessor =
|
||||
new Microsoft.ApplicationInspector.RulesEngine.RuleProcessor(rules, new RuleProcessorOptions());
|
||||
_languages.FromFileNameOut("testfile.cs", out LanguageInfo info);
|
||||
Assert.AreEqual(numIssues,
|
||||
ruleProcessor.AnalyzeFile(content, new FileEntry("testfile.cs", new MemoryStream()), info).Count());
|
||||
}
|
||||
}
|
|
@ -1,9 +1,6 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using Microsoft.ApplicationInspector.RulesEngine;
|
||||
using Microsoft.CST.RecursiveExtractor;
|
||||
using Microsoft.VisualBasic.CompilerServices;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace AppInspector.Tests.RuleProcessor;
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
[
|
||||
{
|
||||
"name": "SaaS: Salesforce",
|
||||
"id": "AI060001",
|
||||
"description": "SaaS: Salesforce Rest API",
|
||||
"tags": [
|
||||
"CloudServices.Salesforce"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"confidence": "high",
|
||||
"pattern": "my\\.salesforce\\.com",
|
||||
"type": "regex",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"modifiers": [
|
||||
"i"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "SaaS: ServiceNow",
|
||||
"id": "AI060002",
|
||||
"description": "SaaS: ServiceNow Rest API",
|
||||
"tags": [
|
||||
"CloudServices.ServiceNow"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"confidence": "high",
|
||||
"pattern": "service-now\\.com/api",
|
||||
"type": "regex",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"modifiers": [
|
||||
"i"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
,
|
||||
{
|
||||
"name": "SaaS: WorkDay",
|
||||
"id": "AI060000",
|
||||
"description": "SaaS: WorkDay Rest API",
|
||||
"tags": [
|
||||
"CloudServices.WorkDay"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"confidence": "high",
|
||||
"pattern": "workday.com",
|
||||
"type": "regex",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"modifiers": [
|
||||
"i"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
Загрузка…
Ссылка в новой задаче