Skip to content

Commit 3e6a87e

Browse files
Add tests to identify rules with missing or incomplete guidance (#613)
* Add tests to identify rules with missing or incomplete guidance * Also consider guidance with "TO DO" incomplete * Point DES rules at same guidance * Add guidance for .NET TLS config * Add guidance for .NET Framework 4.7.2 rule * Add guidance for .NET Core advisory 4021279 * Add guidance for Microsoft.IdentityModel.Tokens rule * Add guidance for unsafe keyword rule * Add guidance for JS setTimeout rule * Add guidance for weak/broken hash algo rule * Add guidance for disabling cert validation rule * Add guidance for avoid $_REQUEST rule * Add guidance for PHP XSS rule * Add guidance for strlen rule * Add guidance for Python datetime rule * Add changelog for guidance changes * Add debug info to guidance tests to troubleshoot CI * Fix finding guidance for DevSkim CLI in CI
1 parent 76125aa commit 3e6a87e

30 files changed

+358
-110
lines changed

Changelog.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7-
## [1.0.35] - 2024-05-21
7+
## [1.0.37] - 2024-5-23
8+
### Missing Guidance
9+
Added guidance for several rules such as weak hash algorithm, disabling certificate validation, and TLS client configuration.
10+
11+
## [1.0.36] - 2024-05-21
812
### Rules
913
Fix substitution pattern in PHP Request rule.
1014

DevSkim-DotNet/Microsoft.DevSkim.Tests/DefaultRulesTests.cs

Lines changed: 98 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,49 @@ namespace Microsoft.DevSkim.Tests;
33
[TestClass]
44
public class DefaultRulesTests
55
{
6+
private static string _guidanceDirectory = string.Empty;
7+
8+
[ClassInitialize]
9+
public static void ClassInitialize(TestContext testContext)
10+
{
11+
string directory = Directory.GetCurrentDirectory();
12+
13+
/* Given a directory, like: "C:\src\DevSkim\DevSkim-DotNet\Microsoft.DevSkim.Tests\bin\Debug\net8.0" - local dev
14+
* OR "/mnt/vss/_work/1/s/DevSkim-DotNet/Microsoft.DevSkim.Tests/bin/Debug/net8.0" - CI for DevSkim CLI
15+
* we want to find: "C:\src\DevSkim\guidance"
16+
*
17+
* so we look for DevSkim-DotNet and then go up one more level to find guidance.
18+
*/
19+
20+
var currentDirInfo = new DirectoryInfo(directory);
21+
while (currentDirInfo != null && currentDirInfo.Name != "DevSkim-DotNet")
22+
{
23+
currentDirInfo = currentDirInfo.Parent;
24+
}
25+
26+
currentDirInfo = currentDirInfo?.Parent;
27+
28+
if (currentDirInfo == null)
29+
{
30+
string message = $"Could not find DevSkim-DotNet directory from: {directory}.";
31+
throw new Exception(message);
32+
}
33+
34+
string guidanceDir = Path.Combine(currentDirInfo.FullName, "guidance");
35+
if (!Directory.Exists(guidanceDir))
36+
{
37+
throw new Exception($"Guidance directory {guidanceDir} does not exist.");
38+
}
39+
40+
_guidanceDirectory = guidanceDir;
41+
}
42+
643
[TestMethod]
744
public void ValidateDefaultRules()
845
{
9-
DevSkimRuleSet devSkimRuleSet = DevSkim.DevSkimRuleSet.GetDefaultRuleSet();
46+
DevSkimRuleSet devSkimRuleSet = DevSkimRuleSet.GetDefaultRuleSet();
1047
Assert.AreNotEqual(0, devSkimRuleSet.Count());
11-
DevSkimRuleVerifier validator = new DevSkim.DevSkimRuleVerifier(new DevSkimRuleVerifierOptions()
48+
var validator = new DevSkimRuleVerifier(new DevSkimRuleVerifierOptions()
1249
{
1350
LanguageSpecs = DevSkimLanguages.LoadEmbedded()
1451
});
@@ -80,4 +117,63 @@ public void DenamespacedRule()
80117
IEnumerable<Issue> analysis = analyzer.Analyze(content, "thing.xml");
81118
Assert.AreEqual(1, analysis.Count());
82119
}
120+
121+
public static IEnumerable<object[]> DefaultRules
122+
{
123+
get
124+
{
125+
DevSkimRuleSet devSkimRuleSet = DevSkimRuleSet.GetDefaultRuleSet();
126+
foreach (DevSkimRule rule in devSkimRuleSet)
127+
{
128+
yield return new object[] { rule };
129+
}
130+
}
131+
}
132+
133+
[TestMethod]
134+
[DynamicData(nameof(DefaultRules))]
135+
public void Rule_guidance_file_should_be_specified_and_exist(DevSkimRule rule)
136+
{
137+
if (rule.Disabled)
138+
{
139+
Assert.Inconclusive("Rule is disabled.");
140+
}
141+
142+
if (string.IsNullOrEmpty(rule.RuleInfo))
143+
{
144+
Assert.Fail("Rule does not specify guidance file.");
145+
}
146+
147+
string guidanceFile = Path.Combine(_guidanceDirectory, rule.RuleInfo);
148+
Assert.IsTrue(File.Exists(guidanceFile), $"Guidance file {guidanceFile} does not exist.");
149+
}
150+
151+
[Ignore] // TODO: temporary to get missing guidance in.
152+
[TestMethod]
153+
[DynamicData(nameof(DefaultRules))]
154+
public void Rule_guidance_should_be_complete(DevSkimRule rule)
155+
{
156+
if (rule.Disabled)
157+
{
158+
Assert.Inconclusive("Rule is disabled.");
159+
}
160+
161+
if(string.IsNullOrEmpty(rule.RuleInfo))
162+
{
163+
Assert.Inconclusive("Rule does not specify guidance file.");
164+
}
165+
166+
string guidanceFile = Path.Combine(_guidanceDirectory, rule.RuleInfo);
167+
if(!File.Exists(guidanceFile))
168+
{
169+
Assert.Inconclusive("Guidance file does not exist");
170+
}
171+
172+
string guidance = File.ReadAllText(guidanceFile);
173+
if(guidance.Contains("TODO", StringComparison.OrdinalIgnoreCase)
174+
|| guidance.Contains("TO DO", StringComparison.OrdinalIgnoreCase))
175+
{
176+
Assert.Fail($"Guidance file {guidanceFile} contains TODO.");
177+
}
178+
}
83179
}

DevSkim-DotNet/Microsoft.DevSkim/DevSkimRule.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,10 @@ public class DevSkimRule : Rule
2222
[JsonProperty(PropertyName = "rule_info")]
2323
[JsonPropertyName("rule_info")]
2424
public string? RuleInfo { get; set; }
25+
26+
public override string ToString()
27+
{
28+
return $"'{Id}: {Name}'";
29+
}
2530
}
2631
}

guidance/DS106864.md

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
1-
## Do not use the DES symmetric block cipher.
1+
# Do not use the DES symmetric block cipher
2+
3+
## Summary
24

3-
### Summary
45
The DES cipher was found, which is widely considered to be broken.
56

6-
### Details
7+
## Details
8+
79
The [Data Encryption Standard](https://en.wikipedia.org/wiki/Data_Encryption_Standard), or DES,
810
is a symmetric block cipher created in the 1970s. It has since been broken and should not be used
911
anywhere.
1012

1113
In general, the [Advanced Encryption Standard](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard),
1214
or AES, algorithm, is preferred for all cases where symmetric encryption is needed.
1315

14-
#### Solution
16+
### Solution
1517

16-
##### .NET
18+
#### .NET
1719

1820
Use the following method: `System.Security.Cryptography.Aes.Create()`
1921

@@ -36,7 +38,7 @@ It can also be accessed through the following factory methods:
3638
On Windows (C/C++), DES is available through the following:
3739

3840
* The algorithm identifier `CALG_DES` can be passed to various methods, including
39-
[CryptDeriveKey](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379916(v=vs.85).aspx).
41+
[CryptDeriveKey](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379916(v=vs.85).aspx).
4042
* The algorithm identifier `BCRYPT_DES_ALGORITHM` can be passed to
4143
[BCryptOpenAlgorithmProvider](https://msdn.microsoft.com/en-us/library/windows/desktop/aa375479(v=vs.85).aspx).
4244

@@ -52,5 +54,4 @@ OpenSSL) makes the DES algorithm available through the following calls:
5254

5355
### Severity Considerations
5456

55-
Any use of the DES algorithm should be very carefully reviewed by a security expert or cryptographer
56-
to understand the risks involved.
57+
Any use of the DES algorithm should be very carefully reviewed by a security expert or cryptographer to understand the risks involved.

guidance/DS108647.md

Lines changed: 0 additions & 11 deletions
This file was deleted.

guidance/DS112835.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# SSL/TLS Cryptographic Agility Guidance
2+
3+
## Summary
4+
5+
* .NET Framework applications should target .NET Framework 4.8 or later for TLS 1.3 support.
6+
* Do not specify the TLS version explicitly. Configure your code to let the OS decide on the TLS version.
7+
* Do not disable the use of strong cryptography for TLS via configuration.
8+
9+
## Details
10+
11+
### Defer Choice of TLS Version to OS
12+
13+
The Transport Layer Security (TLS) protocol is a cryptographic standard designed to help protect the privacy of information communicated over the Internet. Cryptographic algorithms once considered secure may become insecure due to advances in computing power or discovery of subtle flaws in the algorithms.
14+
15+
Software with hardcoded cryptographic algorithms may require code changes in the future if those algorithms become insecure. A better alternative is to defer control of the cryptographic algorithm to the operating system.
16+
17+
### Implementation
18+
19+
#### .NET
20+
21+
* When `Switch.System.ServiceModel.DontEnableSystemDefaultTlsVersions` is `false`, the application will use TLS protocol chosen by the operating system. Do not set `DontEnableSystemDefaultTlsVersions` to `false`.
22+
* When `Switch.System.Net.DontEnableSchUseStrongCrypto` is `false`, the application will use more secure network protocols. Do not set `DontEnableSchUseStrongCrypto` to `true`.
23+
* When application code sets a value for `System.Net.ServicePointManager.SecurityProtocol`, the application will override the TLS protocol chosen by the operating system. This makes the application less crypto-agile and may make the application less secure. Do not set a value for `System.Net.ServicePointManager.SecurityProtocol` in application code.
24+
25+
## References
26+
27+
* [TLS Best Practices with .NET Framework](https://learn.microsoft.com/en-us/dotnet/framework/network-programming/tls)
28+
* [Security Briefs - Cryptographic Agility](https://learn.microsoft.com/en-us/archive/msdn-magazine/2009/august/cryptographic-agility)
29+
* [Microsoft SDL Cryptographic Recommendations](http://download.microsoft.com/download/6/3/A/63AFA3DF-BB84-4B38-8704-B27605B99DA7/Microsoft%20SDL%20Cryptographic%20Recommendations.pdf)
30+
* [SSL Labs: SSL and TLS Deployment Best Practices](https://github.com/ssllabs/research/wiki/SSL-and-TLS-Deployment-Best-Practices)
31+
* [OWASP: Transport Layer Protection Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Security_Cheat_Sheet.html)

guidance/DS126858.md

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,25 @@
1-
## Weak/Broken Hash Algorithm
1+
# Weak/Broken Hash Algorithm
2+
3+
## Summary
24

3-
### Summary
45
A weak or broken hash algorithm was detected.
6+
Any usage of MD2, MD4, MD5 or SHA-1 is considered insecure.
7+
Replace the use of insecure hashing algorithms with more secure alternatives such as an algorithm from the SHA-2 family (SHA256, SHA384, and SHA512).
8+
9+
## Details
10+
11+
Hash collisions are computationally feasible for older, weak hash algorithms such as MD2, MD4, MD5, and SHA-1.
12+
A hash collision allows an attacker to substitute an alternative input that results in the same hash value.
13+
Collision attacks allow attackers to undermine the security of systems using an insecure hash algorithm (e.g., by forging digital signatures, concealing data tampering, or cracking passwords).
14+
15+
## Solution
516

6-
### Details
7-
The use of signers like `MD5WithRSAEncryption` in cryptography providers like BouncyCastle
8-
is susceptible to colission attacks. Anything that uses MD2, MD4, MD5 or SHA-1 is considered
9-
insecure.
17+
### .NET
1018

11-
Replace the use of insecure hashing algorithms with more secure alternatives, from SHA256 onward.
12-
See the list of available BouncyCastle signers here:
13-
https://github.com/neoeinstein/bouncycastle/blob/master/crypto/src/security/SignerUtilities.cs.
19+
Replace usages of insecure hash algorithms with `System.Security.Cryptography.SHA512Cng`, `System.Security.Cryptography.SHA384Cng`, or `System.Security.Cryptography.SHA256Cng`.
1420

15-
For more information, see https://codeql.github.com/codeql-query-help/python/py-weak-sensitive-data-hashing/.
21+
### Python
1622

17-
### Severity Considerations
18-
Data signed using broken hash algorithms like MD2, MD4, MD5 and SHA1 can be broken using specially designed hardware/software.
23+
The use of signers like `MD5WithRSAEncryption` in cryptography providers like BouncyCastle is susceptible to collision attacks. See the list of available [BouncyCastle signers](https://github.com/neoeinstein/bouncycastle/blob/master/crypto/src/security/SignerUtilities.cs).
1924

25+
For more information, see [CodeQL Python Hash Algorithm Guidance](https://codeql.github.com/codeql-query-help/python/py-weak-sensitive-data-hashing/).

guidance/DS140021.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Banned C function detected (strlen)
2+
3+
## Summary
4+
5+
* Use of the `strlen` function to determine the length of a string can lead to a buffer overrun vulnerability.
6+
* Use secure versions such as `strlen_s` or `strnlen` to help prevent buffer overruns.
7+
8+
## Details
9+
10+
The `strlen` function counts characters until the null terminator is encountered.
11+
When a string is missing the null terminator, the resulting value returned is larger than the string.
12+
Code that relies on the result of `strlen` can suffer from a buffer overrun vulnerability.
13+
14+
## Severity Considerations
15+
16+
In the worst case, a buffer overrun vulnerability can provide an attacker the ability to execute arbitrary code leading to complete system compromise.
17+
18+
## Solution
19+
20+
Use secure versions such as `strlen_s` or `strnlen` to help prevent buffer overruns. See [Microsoft C Runtime Reference: strnlen](https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/strnlen-strnlen-s) for more information.
21+
22+
## References
23+
24+
* [Avoiding Buffer Overruns](https://learn.microsoft.com/en-us/windows/win32/SecBP/avoiding-buffer-overruns)
25+
* [Microsoft C Runtime Reference: strlen](https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/strlen-wcslen-mbslen-mbslen-l-mbstrlen-mbstrlen-l)
26+
* [Microsoft C Runtime Reference: strnlen](https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/strnlen-strnlen-s)

guidance/DS144886.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# $_REQUEST should be avoided
2+
3+
## Description
4+
5+
`$_REQUEST` combines POST, GET, and cookie values in one array, making it easy for an attacker to modify a POST or cookie value by instead putting it in a querystring parameter and sending the URL to the victim.
6+
7+
## Solution
8+
9+
Use $_POST, $_GET, $_COOKIE to scope to the expected delivery method for a value.
10+
11+
## References
12+
13+
* [OWASP PHP Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/PHP_Configuration_Cheat_Sheet.html#Use_of_.24_REQUEST)

guidance/DS163877.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Do not echo unencoded GET/POST/COOKIE values
2+
3+
## Description
4+
5+
When using $_GET/POST/COOKIE values via echo, failure to encode the values will lead to Cross Site Scripting (XSS), where a malicious party can inject script into the webpage.
6+
7+
## Solution
8+
9+
HTML Entity Encode (for content going into HTML) or URL Encode (for content going into JavaScript variables) the data.
10+
11+
## References
12+
13+
- [OWASP XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html)

0 commit comments

Comments
 (0)