- 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.
192 lines
6.7 KiB
C#
192 lines
6.7 KiB
C#
// =============================================================================
|
|
// A01_BrokenAccessControl/AuthorizationBypassTests.cs
|
|
// OWASP A01:2021 - Broken Access Control
|
|
// Tests for authorization bypass vulnerabilities
|
|
// =============================================================================
|
|
|
|
using FluentAssertions;
|
|
using StellaOps.Security.Tests.Infrastructure;
|
|
|
|
namespace StellaOps.Security.Tests.A01_BrokenAccessControl;
|
|
|
|
/// <summary>
|
|
/// Tests for broken access control vulnerabilities including:
|
|
/// - Horizontal privilege escalation (accessing other users' data)
|
|
/// - Vertical privilege escalation (accessing admin functions)
|
|
/// - IDOR (Insecure Direct Object Reference)
|
|
/// - Path-based access control bypass
|
|
/// </summary>
|
|
[Trait("Category", "Security")]
|
|
[Trait("OWASP", "A01")]
|
|
[OwaspCategory("A01:2021", "Broken Access Control")]
|
|
public class AuthorizationBypassTests : SecurityTestBase
|
|
{
|
|
[Fact]
|
|
public void Should_Reject_Cross_Tenant_Access_Attempt()
|
|
{
|
|
// Arrange
|
|
var tenantA = GenerateTestTenantId();
|
|
var tenantB = GenerateTestTenantId();
|
|
var userFromTenantA = GenerateTestUserId();
|
|
|
|
// Act & Assert
|
|
// Simulates checking that a user from Tenant A cannot access Tenant B resources
|
|
// In real implementation, this would test the actual authorization service
|
|
tenantA.Should().NotBe(tenantB, "Test setup: tenants should be different");
|
|
|
|
// The authorization check should prevent cross-tenant access
|
|
var authorizationResult = SimulateCrossTenantAccessCheck(tenantA, tenantB, userFromTenantA);
|
|
authorizationResult.Should().BeFalse("Cross-tenant access should be denied");
|
|
}
|
|
|
|
[Fact]
|
|
public void Should_Reject_IDOR_Attack_On_Resource_Id()
|
|
{
|
|
// Arrange
|
|
var authenticatedUserId = GenerateTestUserId();
|
|
var otherUserId = GenerateTestUserId();
|
|
|
|
// Act - Attempt to access another user's resource by ID manipulation
|
|
var canAccessOtherUserResource = SimulateIdorCheck(authenticatedUserId, otherUserId);
|
|
|
|
// Assert
|
|
canAccessOtherUserResource.Should().BeFalse(
|
|
"User should not access resources of another user via IDOR");
|
|
}
|
|
|
|
[Fact]
|
|
public void Should_Reject_Admin_Function_Access_By_Regular_User()
|
|
{
|
|
// Arrange
|
|
var regularUserId = GenerateTestUserId();
|
|
var isAdmin = false;
|
|
|
|
// Act - Attempt to access admin-only function
|
|
var canAccessAdminFunction = SimulateAdminFunctionCheck(regularUserId, isAdmin);
|
|
|
|
// Assert
|
|
canAccessAdminFunction.Should().BeFalse(
|
|
"Regular user should not access admin functions");
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("/api/admin/users", false)]
|
|
[InlineData("/api/admin/settings", false)]
|
|
[InlineData("/api/admin/audit-logs", false)]
|
|
[InlineData("/api/v1/scans", true)] // Regular endpoint - should be accessible
|
|
public void Should_Enforce_Path_Based_Authorization(string path, bool shouldBeAccessible)
|
|
{
|
|
// Arrange
|
|
var regularUserId = GenerateTestUserId();
|
|
|
|
// Act
|
|
var canAccess = SimulatePathBasedAuth(path, regularUserId, isAdmin: false);
|
|
|
|
// Assert
|
|
canAccess.Should().Be(shouldBeAccessible,
|
|
$"Path {path} should {(shouldBeAccessible ? "" : "not ")}be accessible to regular users");
|
|
}
|
|
|
|
[Fact]
|
|
public void Should_Prevent_Parameter_Tampering_For_Ownership()
|
|
{
|
|
// Arrange
|
|
var authenticatedUserId = GenerateTestUserId();
|
|
var tamperedOwnerId = GenerateTestUserId(); // Attacker tries to claim ownership
|
|
|
|
// Act - Simulate API call where attacker modifies owner_id parameter
|
|
var result = SimulateOwnershipTamperingCheck(authenticatedUserId, tamperedOwnerId);
|
|
|
|
// Assert
|
|
result.Should().BeFalse("Parameter tampering for ownership should be rejected");
|
|
}
|
|
|
|
[Fact]
|
|
public void Should_Enforce_Method_Level_Authorization()
|
|
{
|
|
// Arrange
|
|
var userId = GenerateTestUserId();
|
|
var resourceId = Guid.NewGuid();
|
|
|
|
// User has READ but not WRITE permission
|
|
var readAllowed = true;
|
|
var writeAllowed = false;
|
|
|
|
// Act & Assert
|
|
SimulateMethodAuth(userId, resourceId, "GET", readAllowed).Should().BeTrue();
|
|
SimulateMethodAuth(userId, resourceId, "DELETE", writeAllowed).Should().BeFalse(
|
|
"User with read-only permission should not delete resources");
|
|
}
|
|
|
|
[Fact]
|
|
public void Should_Validate_JWT_Claims_For_Authorization()
|
|
{
|
|
// Arrange - JWT with tampered claims
|
|
var tamperedToken = MaliciousPayloads.JwtAttacks.NoneAlgorithm;
|
|
|
|
// Act & Assert
|
|
var action = () => ValidateJwtForAuth(tamperedToken);
|
|
action.Should().Throw<Exception>("Tampered JWT should be rejected");
|
|
}
|
|
|
|
#region Simulation Helpers
|
|
|
|
private static bool SimulateCrossTenantAccessCheck(Guid requestorTenant, Guid targetTenant, Guid userId)
|
|
{
|
|
// In real implementation, this would call the authorization service
|
|
// For test purposes, we verify the logic exists
|
|
return requestorTenant == targetTenant;
|
|
}
|
|
|
|
private static bool SimulateIdorCheck(Guid authenticatedUserId, Guid resourceOwnerId)
|
|
{
|
|
// Proper IDOR protection requires ownership verification
|
|
return authenticatedUserId == resourceOwnerId;
|
|
}
|
|
|
|
private static bool SimulateAdminFunctionCheck(Guid userId, bool isAdmin)
|
|
{
|
|
// Admin functions require admin role
|
|
return isAdmin;
|
|
}
|
|
|
|
private static bool SimulatePathBasedAuth(string path, Guid userId, bool isAdmin)
|
|
{
|
|
// Admin paths require admin role
|
|
if (path.StartsWith("/api/admin", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
return isAdmin;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private static bool SimulateOwnershipTamperingCheck(Guid authenticatedUserId, Guid claimedOwnerId)
|
|
{
|
|
// The claimed owner must match the authenticated user
|
|
return authenticatedUserId == claimedOwnerId;
|
|
}
|
|
|
|
private static bool SimulateMethodAuth(Guid userId, Guid resourceId, string method, bool hasPermission)
|
|
{
|
|
// Method-level authorization check
|
|
return hasPermission;
|
|
}
|
|
|
|
private static void ValidateJwtForAuth(string token)
|
|
{
|
|
// Simulate JWT validation that should reject invalid tokens
|
|
if (token.EndsWith('.') || token.Split('.').Length != 3)
|
|
{
|
|
throw new InvalidOperationException("Invalid JWT format");
|
|
}
|
|
|
|
var parts = token.Split('.');
|
|
if (string.IsNullOrEmpty(parts[2]))
|
|
{
|
|
throw new InvalidOperationException("JWT signature is missing");
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|