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:
Gabe Stocco 2023-07-27 16:53:35 -07:00 коммит произвёл GitHub
Родитель 4bb352a0c0
Коммит 8a78a5260c
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
12 изменённых файлов: 208 добавлений и 18 удалений

Просмотреть файл

@ -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"
]
}
]
}
]