Add comprehensive security tests for OWASP A03 (Injection) and A10 (SSRF)
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled

- Implemented InjectionTests.cs to cover various injection vulnerabilities including SQL, NoSQL, Command, LDAP, and XPath injections.
- Created SsrfTests.cs to test for Server-Side Request Forgery (SSRF) vulnerabilities, including internal URL access, cloud metadata access, and URL allowlist bypass attempts.
- Introduced MaliciousPayloads.cs to store a collection of malicious payloads for testing various security vulnerabilities.
- Added SecurityAssertions.cs for common security-specific assertion helpers.
- Established SecurityTestBase.cs as a base class for security tests, providing common infrastructure and mocking utilities.
- Configured the test project StellaOps.Security.Tests.csproj with necessary dependencies for testing.
This commit is contained in:
master
2025-12-16 13:11:57 +02:00
parent 5a480a3c2a
commit b55d9fa68d
72 changed files with 8051 additions and 71 deletions

View File

@@ -0,0 +1,300 @@
using StellaOps.Attestor.Core.Verification;
using Xunit;
namespace StellaOps.Attestor.Tests;
public sealed class MerkleProofVerifierTests
{
[Fact]
public void HashLeaf_ProducesDeterministicHash()
{
var data = "test data"u8.ToArray();
var hash1 = MerkleProofVerifier.HashLeaf(data);
var hash2 = MerkleProofVerifier.HashLeaf(data);
Assert.Equal(hash1, hash2);
Assert.Equal(32, hash1.Length); // SHA-256 produces 32 bytes
}
[Fact]
public void HashLeaf_IncludesLeafPrefix()
{
var data = Array.Empty<byte>();
var hash = MerkleProofVerifier.HashLeaf(data);
// Hash of 0x00 prefix only should be consistent
Assert.NotNull(hash);
Assert.Equal(32, hash.Length);
}
[Fact]
public void HashInterior_ProducesDeterministicHash()
{
var left = new byte[] { 1, 2, 3 };
var right = new byte[] { 4, 5, 6 };
var hash1 = MerkleProofVerifier.HashInterior(left, right);
var hash2 = MerkleProofVerifier.HashInterior(left, right);
Assert.Equal(hash1, hash2);
}
[Fact]
public void HashInterior_OrderMatters()
{
var a = new byte[] { 1, 2, 3 };
var b = new byte[] { 4, 5, 6 };
var hashAB = MerkleProofVerifier.HashInterior(a, b);
var hashBA = MerkleProofVerifier.HashInterior(b, a);
Assert.NotEqual(hashAB, hashBA);
}
[Fact]
public void VerifyInclusion_SingleLeafTree_Succeeds()
{
var leafData = "single leaf"u8.ToArray();
var leafHash = MerkleProofVerifier.HashLeaf(leafData);
// In a single-leaf tree, root = leaf hash
var verified = MerkleProofVerifier.VerifyInclusion(
leafHash,
leafIndex: 0,
treeSize: 1,
proofHashes: Array.Empty<byte[]>(),
expectedRootHash: leafHash);
Assert.True(verified);
}
[Fact]
public void VerifyInclusion_TwoLeafTree_LeftLeaf_Succeeds()
{
var leaf0Data = "leaf 0"u8.ToArray();
var leaf1Data = "leaf 1"u8.ToArray();
var leaf0Hash = MerkleProofVerifier.HashLeaf(leaf0Data);
var leaf1Hash = MerkleProofVerifier.HashLeaf(leaf1Data);
var rootHash = MerkleProofVerifier.HashInterior(leaf0Hash, leaf1Hash);
// Verify leaf 0 with sibling leaf 1
var verified = MerkleProofVerifier.VerifyInclusion(
leaf0Hash,
leafIndex: 0,
treeSize: 2,
proofHashes: new[] { leaf1Hash },
expectedRootHash: rootHash);
Assert.True(verified);
}
[Fact]
public void VerifyInclusion_TwoLeafTree_RightLeaf_Succeeds()
{
var leaf0Data = "leaf 0"u8.ToArray();
var leaf1Data = "leaf 1"u8.ToArray();
var leaf0Hash = MerkleProofVerifier.HashLeaf(leaf0Data);
var leaf1Hash = MerkleProofVerifier.HashLeaf(leaf1Data);
var rootHash = MerkleProofVerifier.HashInterior(leaf0Hash, leaf1Hash);
// Verify leaf 1 with sibling leaf 0
var verified = MerkleProofVerifier.VerifyInclusion(
leaf1Hash,
leafIndex: 1,
treeSize: 2,
proofHashes: new[] { leaf0Hash },
expectedRootHash: rootHash);
Assert.True(verified);
}
[Fact]
public void VerifyInclusion_InvalidLeafHash_Fails()
{
var leaf0Data = "leaf 0"u8.ToArray();
var leaf1Data = "leaf 1"u8.ToArray();
var tamperedData = "tampered"u8.ToArray();
var leaf0Hash = MerkleProofVerifier.HashLeaf(leaf0Data);
var leaf1Hash = MerkleProofVerifier.HashLeaf(leaf1Data);
var tamperedHash = MerkleProofVerifier.HashLeaf(tamperedData);
var rootHash = MerkleProofVerifier.HashInterior(leaf0Hash, leaf1Hash);
// Try to verify tampered leaf
var verified = MerkleProofVerifier.VerifyInclusion(
tamperedHash,
leafIndex: 0,
treeSize: 2,
proofHashes: new[] { leaf1Hash },
expectedRootHash: rootHash);
Assert.False(verified);
}
[Fact]
public void VerifyInclusion_WrongRootHash_Fails()
{
var leaf0Hash = MerkleProofVerifier.HashLeaf("leaf 0"u8.ToArray());
var leaf1Hash = MerkleProofVerifier.HashLeaf("leaf 1"u8.ToArray());
var wrongRoot = MerkleProofVerifier.HashLeaf("wrong"u8.ToArray());
var verified = MerkleProofVerifier.VerifyInclusion(
leaf0Hash,
leafIndex: 0,
treeSize: 2,
proofHashes: new[] { leaf1Hash },
expectedRootHash: wrongRoot);
Assert.False(verified);
}
[Fact]
public void VerifyInclusion_InvalidIndex_Fails()
{
var leafHash = MerkleProofVerifier.HashLeaf("test"u8.ToArray());
// Index out of range
var verified = MerkleProofVerifier.VerifyInclusion(
leafHash,
leafIndex: 10,
treeSize: 2,
proofHashes: Array.Empty<byte[]>(),
expectedRootHash: leafHash);
Assert.False(verified);
}
[Fact]
public void VerifyInclusion_NegativeIndex_Fails()
{
var leafHash = MerkleProofVerifier.HashLeaf("test"u8.ToArray());
var verified = MerkleProofVerifier.VerifyInclusion(
leafHash,
leafIndex: -1,
treeSize: 1,
proofHashes: Array.Empty<byte[]>(),
expectedRootHash: leafHash);
Assert.False(verified);
}
[Fact]
public void VerifyInclusion_ZeroTreeSize_Fails()
{
var leafHash = MerkleProofVerifier.HashLeaf("test"u8.ToArray());
var verified = MerkleProofVerifier.VerifyInclusion(
leafHash,
leafIndex: 0,
treeSize: 0,
proofHashes: Array.Empty<byte[]>(),
expectedRootHash: leafHash);
Assert.False(verified);
}
[Fact]
public void HexToBytes_ConvertsCorrectly()
{
var hex = "0102030405";
var expected = new byte[] { 1, 2, 3, 4, 5 };
var result = MerkleProofVerifier.HexToBytes(hex);
Assert.Equal(expected, result);
}
[Fact]
public void HexToBytes_Handles0xPrefix()
{
var hex = "0x0102030405";
var expected = new byte[] { 1, 2, 3, 4, 5 };
var result = MerkleProofVerifier.HexToBytes(hex);
Assert.Equal(expected, result);
}
[Fact]
public void BytesToHex_ConvertsCorrectly()
{
var bytes = new byte[] { 0xAB, 0xCD, 0xEF };
var result = MerkleProofVerifier.BytesToHex(bytes);
Assert.Equal("abcdef", result);
}
[Fact]
public void ComputeRootFromPath_WithEmptyPath_ReturnsSingleLeaf()
{
var leafHash = MerkleProofVerifier.HashLeaf("test"u8.ToArray());
var root = MerkleProofVerifier.ComputeRootFromPath(
leafHash,
leafIndex: 0,
treeSize: 1,
proofHashes: Array.Empty<byte[]>());
Assert.NotNull(root);
Assert.Equal(leafHash, root);
}
[Fact]
public void ComputeRootFromPath_WithEmptyPath_NonSingleTree_ReturnsNull()
{
var leafHash = MerkleProofVerifier.HashLeaf("test"u8.ToArray());
var root = MerkleProofVerifier.ComputeRootFromPath(
leafHash,
leafIndex: 0,
treeSize: 5,
proofHashes: Array.Empty<byte[]>());
Assert.Null(root);
}
[Fact]
public void VerifyInclusion_FourLeafTree_AllPositions()
{
// Build a 4-leaf tree manually
var leaves = new[]
{
MerkleProofVerifier.HashLeaf("leaf0"u8.ToArray()),
MerkleProofVerifier.HashLeaf("leaf1"u8.ToArray()),
MerkleProofVerifier.HashLeaf("leaf2"u8.ToArray()),
MerkleProofVerifier.HashLeaf("leaf3"u8.ToArray())
};
// root
// / \
// h01 h23
// / \ / \
// L0 L1 L2 L3
var h01 = MerkleProofVerifier.HashInterior(leaves[0], leaves[1]);
var h23 = MerkleProofVerifier.HashInterior(leaves[2], leaves[3]);
var root = MerkleProofVerifier.HashInterior(h01, h23);
// Verify leaf 0: sibling = leaf1, parent sibling = h23
Assert.True(MerkleProofVerifier.VerifyInclusion(
leaves[0], 0, 4, new[] { leaves[1], h23 }, root));
// Verify leaf 1: sibling = leaf0, parent sibling = h23
Assert.True(MerkleProofVerifier.VerifyInclusion(
leaves[1], 1, 4, new[] { leaves[0], h23 }, root));
// Verify leaf 2: sibling = leaf3, parent sibling = h01
Assert.True(MerkleProofVerifier.VerifyInclusion(
leaves[2], 2, 4, new[] { leaves[3], h01 }, root));
// Verify leaf 3: sibling = leaf2, parent sibling = h01
Assert.True(MerkleProofVerifier.VerifyInclusion(
leaves[3], 3, 4, new[] { leaves[2], h01 }, root));
}
}