Introduction to Contrast Security
Contrast Security provides runtime application self-protection (RASP) and interactive application security testing (IAST) capabilities through its Java agent. The agent instruments application code to provide real-time security protection and vulnerability detection without requiring code changes.
Table of Contents
- Contrast Agent Architecture
- Agent Installation & Configuration
- Vulnerability Detection
- Attack Protection
- Custom Security Rules
- Integration with Applications
- Monitoring & Management
Contrast Agent Architecture
Core Components
package com.contrast.security.agent;
public class ContrastAgentArchitecture {
/*
* Contrast Agent Components:
*
* 1. Class Transformer - Instruments bytecode at class loading
* 2. Security Sensor - Monitors security-sensitive operations
* 3. Policy Engine - Applies security policies
* 4. Event Collector - Gathers security events
* 5. Communication Module - Sends data to Contrast Platform
* 6. Configuration Manager - Manages agent settings
*/
}
Agent Installation & Configuration
Maven Dependency Setup
<!-- Contrast Security Agent --> <dependency> <groupId>com.contrastsecurity</groupId> <artifactId>contrast-agent</artifactId> <version>4.7.0</version> </dependency> <!-- Contrast SDK for programmatic integration --> <dependency> <groupId>com.contrastsecurity</groupId> <artifactId>contrast-sdk-java</artifactId> <version>2.7</version> </dependency>
Agent Configuration
# contrast.properties - Main configuration file # Contrast Platform Connection contrast.server= contrast.api.key= contrast.service.key= contrast.username= # Application Configuration contrast.application.name=MyEnterpriseApp contrast.application.version=1.0.0 contrast.application.tags=production,financial # Agent Behavior contrast.agent.java.standalone_app_name=MyEnterpriseApp contrast.agent.logger.stdout=true contrast.agent.logger.level=INFO # Security Configuration contrast.protection.enable=true contrast.protection.sql.injection=true contrast.protection.command.injection=true contrast.protection.path-traversal=true contrast.protection.xss=true contrast.protection.xxe=true # Assessment Configuration contrast.assess.enable=true contrast.assess.vulnerabilities.enable=true contrast.assess.libraries.enable=true # Performance Configuration contrast.agent.perf.enable=true contrast.agent.perf.session_analysis=true # Advanced Configuration contrast.agent.instrumentation.include=com.mycompany.** contrast.agent.instrumentation.exclude=com.mycompany.internal.** contrast.agent.session_metadata.enable=true
Programmatic Configuration
package com.contrast.security.config;
import com.contrastsecurity.agents.contrast_agent;
import com.contrastsecurity.config.AgentConfig;
import com.contrastsecurity.config.SecurityConfig;
import java.util.Properties;
public class ContrastAgentConfigurator {
public static void configureAgent() {
Properties props = new Properties();
// Connection settings
props.setProperty("contrast.server", "https://app.contrastsecurity.com");
props.setProperty("contrast.api.key", "your-api-key");
props.setProperty("contrast.service.key", "your-service-key");
props.setProperty("contrast.username", "your-username");
// Application settings
props.setProperty("contrast.application.name", "EnterpriseWebApp");
props.setProperty("contrast.application.version", "2.1.0");
props.setProperty("contrast.application.group", "Financial Services");
// Security settings
props.setProperty("contrast.protection.enable", "true");
props.setProperty("contrast.assess.enable", "true");
props.setProperty("contrast.agent.auto_analysis", "true");
// Initialize agent with configuration
try {
contrast_agent.initialize(props);
System.out.println("Contrast Agent initialized successfully");
} catch (Exception e) {
System.err.println("Failed to initialize Contrast Agent: " + e.getMessage());
}
}
public static AgentConfig createAdvancedConfig() {
return AgentConfig.builder()
.serverUrl("https://app.contrastsecurity.com")
.apiKey("your-api-key")
.serviceKey("your-service-key")
.userName("agent-user")
.applicationName("Microservices-Platform")
.applicationVersion("3.0.0")
.applicationTags("production,api,rest")
.enableProtection(true)
.enableAssessment(true)
.enableLibraryAssessment(true)
.enablePerformanceMonitoring(true)
.logLevel("INFO")
.build();
}
}
Vulnerability Detection
SQL Injection Detection
package com.contrast.security.detection;
import java.sql.*;
import javax.sql.DataSource;
public class SQLInjectionDetection {
// Vulnerable method - will be detected by Contrast
public String vulnerableGetUser(String userId) throws SQLException {
String query = "SELECT * FROM users WHERE id = '" + userId + "'";
try (Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb");
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(query)) {
if (rs.next()) {
return rs.getString("username");
}
}
return null;
}
// Secure method - using prepared statements
public String secureGetUser(String userId) throws SQLException {
String query = "SELECT username FROM users WHERE id = ?";
try (Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb");
PreparedStatement stmt = conn.prepareStatement(query)) {
stmt.setString(1, userId);
try (ResultSet rs = stmt.executeQuery()) {
if (rs.next()) {
return rs.getString("username");
}
}
}
return null;
}
// JPA/Hibernate example
@PersistenceContext
private EntityManager entityManager;
// Vulnerable JPA
public User vulnerableJpaGetUser(String userId) {
String jpql = "SELECT u FROM User u WHERE u.id = '" + userId + "'";
TypedQuery<User> query = entityManager.createQuery(jpql, User.class);
return query.getSingleResult();
}
// Secure JPA
public User secureJpaGetUser(String userId) {
String jpql = "SELECT u FROM User u WHERE u.id = :userId";
TypedQuery<User> query = entityManager.createQuery(jpql, User.class);
query.setParameter("userId", userId);
return query.getSingleResult();
}
}
Command Injection Detection
package com.contrast.security.detection;
import java.io.*;
public class CommandInjectionDetection {
// Vulnerable command execution
public void vulnerableExecuteCommand(String filename) throws IOException {
String command = "ls -la " + filename;
Process process = Runtime.getRuntime().exec(command);
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
}
// Secure command execution with validation
public void secureExecuteCommand(String filename) throws IOException {
// Validate filename
if (!isValidFilename(filename)) {
throw new SecurityException("Invalid filename: " + filename);
}
// Use ProcessBuilder with command array
ProcessBuilder pb = new ProcessBuilder("ls", "-la", filename);
Process process = pb.start();
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
}
private boolean isValidFilename(String filename) {
// Simple validation - in production, use more robust validation
return filename != null &&
filename.matches("[a-zA-Z0-9._-]+") &&
!filename.contains("..") &&
!filename.contains("/") &&
!filename.contains("\\");
}
}
Path Traversal Detection
package com.contrast.security.detection;
import java.io.*;
import java.nio.file.*;
public class PathTraversalDetection {
// Vulnerable file access
public String vulnerableReadFile(String filename) throws IOException {
String basePath = "/var/www/files/";
String fullPath = basePath + filename;
return new String(Files.readAllBytes(Paths.get(fullPath)));
}
// Secure file access with path normalization and validation
public String secureReadFile(String filename) throws IOException {
String basePath = "/var/www/files/";
// Normalize path and check for traversal attempts
Path baseDir = Paths.get(basePath).normalize().toAbsolutePath();
Path requestedFile = baseDir.resolve(filename).normalize().toAbsolutePath();
// Ensure the resolved path is still within the base directory
if (!requestedFile.startsWith(baseDir)) {
throw new SecurityException("Path traversal attempt detected: " + filename);
}
// Validate file exists and is readable
if (!Files.exists(requestedFile) || !Files.isReadable(requestedFile)) {
throw new FileNotFoundException("File not found or not readable: " + filename);
}
return new String(Files.readAllBytes(requestedFile));
}
}
Attack Protection
Real-time Attack Blocking
package com.contrast.security.protection;
import com.contrastsecurity.SecurityEvent;
import com.contrastsecurity.SecurityResponse;
import com.contrastsecurity.agents.runtime.ProtectionEngine;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
public class SecurityFilter implements Filter {
private ProtectionEngine protectionEngine;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.protectionEngine = ProtectionEngine.getInstance();
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// Check for attacks before processing the request
SecurityResponse securityResponse = protectionEngine.analyzeRequest(httpRequest);
if (securityResponse.isBlocked()) {
// Block the request and log the security event
handleBlockedRequest(httpResponse, securityResponse);
return;
}
// Continue with request processing
chain.doFilter(request, response);
// Analyze response for potential data leakage
protectionEngine.analyzeResponse(httpRequest, httpResponse);
}
private void handleBlockedRequest(HttpServletResponse response,
SecurityResponse securityResponse) throws IOException {
response.setStatus(403);
response.setContentType("application/json");
String errorJson = String.format(
"{\"error\": \"Request blocked\", \"reason\": \"%s\", \"rule\": \"%s\"}",
securityResponse.getReason(),
securityResponse.getRuleName()
);
response.getWriter().write(errorJson);
// Log the security event
SecurityEvent event = securityResponse.getSecurityEvent();
System.err.println("Security block: " + event.toString());
}
@Override
public void destroy() {
// Cleanup resources
}
}
Custom Security Headers
package com.contrast.security.protection;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
public class SecurityHeadersFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse httpResponse = (HttpServletResponse) response;
// Add security headers
httpResponse.setHeader("X-Content-Type-Options", "nosniff");
httpResponse.setHeader("X-Frame-Options", "DENY");
httpResponse.setHeader("X-XSS-Protection", "1; mode=block");
httpResponse.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
httpResponse.setHeader("Content-Security-Policy",
"default-src 'self'; script-src 'self' 'unsafe-inline'");
chain.doFilter(request, response);
}
}
Custom Security Rules
Custom Vulnerability Detection
package com.contrast.security.rules;
import com.contrastsecurity.CustomRule;
import com.contrastsecurity.SecurityEvent;
import com.contrastsecurity.agents.runtime.RuleEngine;
import com.contrastsecurity.agents.runtime.RuleContext;
public class CustomSecurityRules {
// Custom rule for detecting specific business logic vulnerabilities
@CustomRule(
id = "CUSTOM-001",
name = "Sensitive Data Exposure in Logs",
description = "Detects logging of sensitive information",
category = "CUSTOM",
severity = "MEDIUM"
)
public static class SensitiveDataLoggingRule implements RuleEngine {
private static final String[] SENSITIVE_PATTERNS = {
"password", "credit_card", "ssn", "api_key", "secret"
};
@Override
public SecurityEvent evaluate(RuleContext context) {
Object[] parameters = context.getParameters();
for (Object param : parameters) {
if (param instanceof String) {
String paramValue = (String) param;
for (String pattern : SENSITIVE_PATTERNS) {
if (paramValue.toLowerCase().contains(pattern)) {
return SecurityEvent.builder()
.ruleId("CUSTOM-001")
.description("Potential sensitive data in logs: " + pattern)
.parameterValue(paramValue)
.stackTrace(Thread.currentThread().getStackTrace())
.build();
}
}
}
}
return null; // No vulnerability detected
}
}
// Custom rule for API rate limiting
@CustomRule(
id = "CUSTOM-002",
name = "API Rate Limit Violation",
description = "Detects potential API abuse through rate limiting",
category = "CUSTOM",
severity = "LOW"
)
public static class ApiRateLimitRule implements RuleEngine {
private final Map<String, RequestCounter> requestCounters = new ConcurrentHashMap<>();
private static final int MAX_REQUESTS_PER_MINUTE = 100;
@Override
public SecurityEvent evaluate(RuleContext context) {
String clientIp = context.getClientIp();
String endpoint = context.getEndpoint();
String key = clientIp + ":" + endpoint;
RequestCounter counter = requestCounters.computeIfAbsent(
key, k -> new RequestCounter());
if (counter.incrementAndCheck(MAX_REQUESTS_PER_MINUTE)) {
return SecurityEvent.builder()
.ruleId("CUSTOM-002")
.description("API rate limit exceeded for client: " + clientIp)
.parameterValue("Endpoint: " + endpoint + ", Count: " + counter.getCount())
.build();
}
return null;
}
private static class RequestCounter {
private final AtomicInteger count = new AtomicInteger(0);
private long lastResetTime = System.currentTimeMillis();
public boolean incrementAndCheck(int maxRequests) {
synchronized (this) {
long currentTime = System.currentTimeMillis();
// Reset counter every minute
if (currentTime - lastResetTime > 60000) {
count.set(0);
lastResetTime = currentTime;
}
int currentCount = count.incrementAndGet();
return currentCount > maxRequests;
}
}
public int getCount() {
return count.get();
}
}
}
}
Custom Data Classification
package com.contrast.security.rules;
import com.contrastsecurity.DataClassifier;
import com.contrastsecurity.SensitiveData;
public class CustomDataClassifier implements DataClassifier {
@Override
public SensitiveData classify(String data) {
if (data == null) {
return SensitiveData.NONE;
}
// Check for credit card numbers
if (data.matches(".*\\b(?:\\d[ -]*?){13,16}\\b.*")) {
return SensitiveData.CREDIT_CARD;
}
// Check for social security numbers
if (data.matches(".*\\b\\d{3}-\\d{2}-\\d{4}\\b.*")) {
return SensitiveData.SSN;
}
// Check for API keys
if (data.matches(".*[a-zA-Z0-9]{32,64}.*")) {
return SensitiveData.API_KEY;
}
// Check for email addresses
if (data.matches(".*\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}\\b.*")) {
return SensitiveData.EMAIL;
}
// Custom business-specific sensitive data
if (data.contains("employee_id") || data.contains("salary") ||
data.contains("confidential")) {
return SensitiveData.CUSTOM;
}
return SensitiveData.NONE;
}
}
Integration with Applications
Spring Boot Integration
package com.contrast.security.integration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.servlet.*;
import java.util.Properties;
@SpringBootApplication
public class SecureSpringBootApplication {
public static void main(String[] args) {
// Initialize Contrast Agent before Spring Boot starts
initializeContrastAgent();
SpringApplication.run(SecureSpringBootApplication.class, args);
}
private static void initializeContrastAgent() {
try {
Properties props = new Properties();
props.setProperty("contrast.application.name", "SpringBoot-Enterprise-App");
props.setProperty("contrast.application.version", "2.0.0");
props.setProperty("contrast.protection.enable", "true");
props.setProperty("contrast.assess.enable", "true");
com.contrastsecurity.agents.contrast_agent.initialize(props);
System.out.println("Contrast Agent initialized for Spring Boot application");
} catch (Exception e) {
System.err.println("Failed to initialize Contrast Agent: " + e.getMessage());
}
}
@Configuration
public static class SecurityConfig implements WebMvcConfigurer {
@Bean
public Filter contrastSecurityFilter() {
return new ContrastSecurityFilter();
}
@Bean
public Filter securityHeadersFilter() {
return new SecurityHeadersFilter();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new ContrastSecurityInterceptor());
}
}
}
REST API Security Integration
package com.contrast.security.integration;
import com.contrastsecurity.SecurityMonitor;
import com.contrastsecurity.agents.runtime.ProtectionEngine;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
@RestController
@RequestMapping("/api")
public class SecureApiController {
private final ProtectionEngine protectionEngine;
private final SecurityMonitor securityMonitor;
public SecureApiController() {
this.protectionEngine = ProtectionEngine.getInstance();
this.securityMonitor = SecurityMonitor.getInstance();
}
@PostMapping("/users")
public User createUser(@RequestBody User user, HttpServletRequest request) {
// Validate input against security policies
if (!isValidUserInput(user)) {
throw new SecurityException("Invalid user input detected");
}
// Monitor for security events during processing
securityMonitor.startMonitoring("user-creation");
try {
// Business logic
User createdUser = userService.createUser(user);
// Log security event for successful creation
securityMonitor.logEvent("USER_CREATED",
Map.of("userId", createdUser.getId(), "username", createdUser.getUsername()));
return createdUser;
} catch (Exception e) {
// Log security event for failed creation attempt
securityMonitor.logEvent("USER_CREATION_FAILED",
Map.of("error", e.getMessage(), "username", user.getUsername()));
throw e;
} finally {
securityMonitor.stopMonitoring("user-creation");
}
}
@GetMapping("/sensitive-data/{id}")
public SensitiveData getSensitiveData(@PathVariable String id,
HttpServletRequest request) {
// Check if request should be blocked
if (protectionEngine.shouldBlockRequest(request)) {
throw new SecurityException("Request blocked by security policy");
}
// Monitor data access
securityMonitor.startMonitoring("sensitive-data-access");
try {
SensitiveData data = dataService.getSensitiveData(id);
// Classify and protect sensitive data
return maskSensitiveData(data);
} finally {
securityMonitor.stopMonitoring("sensitive-data-access");
}
}
private boolean isValidUserInput(User user) {
// Input validation logic
return user != null &&
user.getUsername() != null &&
user.getUsername().matches("[a-zA-Z0-9]{3,20}") &&
user.getEmail() != null &&
user.getEmail().contains("@");
}
private SensitiveData maskSensitiveData(SensitiveData data) {
// Mask sensitive fields before returning
if (data.getSsn() != null) {
data.setSsn(maskString(data.getSsn()));
}
if (data.getCreditCard() != null) {
data.setCreditCard(maskString(data.getCreditCard()));
}
return data;
}
private String maskString(String value) {
if (value == null || value.length() <= 4) {
return "****";
}
return "****" + value.substring(value.length() - 4);
}
}
Monitoring & Management
Security Event Monitoring
package com.contrast.security.monitoring;
import com.contrastsecurity.SecurityEvent;
import com.contrastsecurity.SecurityEventListener;
import com.contrastsecurity.agents.runtime.EventCollector;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
public class SecurityEventMonitor implements SecurityEventListener {
private final EventCollector eventCollector;
private final ConcurrentHashMap<String, AtomicLong> eventCounts;
private final AtomicLong totalEvents;
public SecurityEventMonitor() {
this.eventCollector = EventCollector.getInstance();
this.eventCounts = new ConcurrentHashMap<>();
this.totalEvents = new AtomicLong(0);
// Register as event listener
eventCollector.registerListener(this);
}
@Override
public void onSecurityEvent(SecurityEvent event) {
String ruleId = event.getRuleId();
eventCounts.computeIfAbsent(ruleId, k -> new AtomicLong(0)).incrementAndGet();
totalEvents.incrementAndGet();
// Log event details
logSecurityEvent(event);
// Take action based on event severity
handleSecurityEvent(event);
}
private void logSecurityEvent(SecurityEvent event) {
System.err.printf(
"SECURITY EVENT: Rule=%s, Severity=%s, Description=%s, Timestamp=%s%n",
event.getRuleId(),
event.getSeverity(),
event.getDescription(),
event.getTimestamp()
);
// Log stack trace for debugging
if (event.getStackTrace() != null) {
System.err.println("Stack trace:");
for (StackTraceElement element : event.getStackTrace()) {
System.err.println(" " + element.toString());
}
}
}
private void handleSecurityEvent(SecurityEvent event) {
switch (event.getSeverity()) {
case "CRITICAL":
handleCriticalEvent(event);
break;
case "HIGH":
handleHighEvent(event);
break;
case "MEDIUM":
handleMediumEvent(event);
break;
case "LOW":
handleLowEvent(event);
break;
default:
// Ignore or log unknown severity
break;
}
}
private void handleCriticalEvent(SecurityEvent event) {
// Immediate action required
System.err.println("CRITICAL SECURITY EVENT - IMMEDIATE ACTION REQUIRED");
// Send alert to security team
sendSecurityAlert(event);
// Optionally block the request source
blockSourceIfNecessary(event);
}
private void handleHighEvent(SecurityEvent event) {
// High priority - log and alert
System.err.println("HIGH PRIORITY SECURITY EVENT DETECTED");
sendSecurityAlert(event);
}
private void handleMediumEvent(SecurityEvent event) {
// Medium priority - log for review
System.err.println("MEDIUM PRIORITY SECURITY EVENT DETECTED");
}
private void handleLowEvent(SecurityEvent event) {
// Low priority - log for informational purposes
System.err.println("LOW PRIORITY SECURITY EVENT DETECTED");
}
private void sendSecurityAlert(SecurityEvent event) {
// Implementation for sending alerts (email, Slack, PagerDuty, etc.)
// This would integrate with your alerting system
}
private void blockSourceIfNecessary(SecurityEvent event) {
// Implementation for blocking malicious sources
// This could involve updating firewall rules or application-level blocking
}
public SecurityMetrics getMetrics() {
return new SecurityMetrics(
totalEvents.get(),
new HashMap<>(eventCounts)
);
}
public static class SecurityMetrics {
private final long totalEvents;
private final Map<String, Long> eventsByRule;
public SecurityMetrics(long totalEvents, Map<String, Long> eventsByRule) {
this.totalEvents = totalEvents;
this.eventsByRule = eventsByRule;
}
// Getters
public long getTotalEvents() { return totalEvents; }
public Map<String, Long> getEventsByRule() { return eventsByRule; }
}
}
Performance Monitoring
package com.contrast.security.monitoring;
import com.contrastsecurity.agents.runtime.PerformanceMonitor;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.ThreadMXBean;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class AgentPerformanceMonitor {
private final PerformanceMonitor performanceMonitor;
private final ScheduledExecutorService scheduler;
private final MemoryMXBean memoryBean;
private final ThreadMXBean threadBean;
public AgentPerformanceMonitor() {
this.performanceMonitor = PerformanceMonitor.getInstance();
this.scheduler = Executors.newScheduledThreadPool(1);
this.memoryBean = ManagementFactory.getMemoryMXBean();
this.threadBean = ManagementFactory.getThreadMXBean();
startMonitoring();
}
private void startMonitoring() {
// Schedule periodic performance checks
scheduler.scheduleAtFixedRate(this::checkPerformance, 0, 30, TimeUnit.SECONDS);
}
private void checkPerformance() {
try {
// Check memory usage
checkMemoryUsage();
// Check thread usage
checkThreadUsage();
// Check agent performance impact
checkAgentPerformance();
} catch (Exception e) {
System.err.println("Error in performance monitoring: " + e.getMessage());
}
}
private void checkMemoryUsage() {
long usedMemory = memoryBean.getHeapMemoryUsage().getUsed();
long maxMemory = memoryBean.getHeapMemoryUsage().getMax();
double memoryUsagePercent = (double) usedMemory / maxMemory * 100;
if (memoryUsagePercent > 80) {
System.err.printf("High memory usage: %.2f%%%n", memoryUsagePercent);
performanceMonitor.recordEvent("HIGH_MEMORY_USAGE",
Map.of("usagePercent", String.valueOf(memoryUsagePercent)));
}
}
private void checkThreadUsage() {
int threadCount = threadBean.getThreadCount();
int peakThreadCount = threadBean.getPeakThreadCount();
if (threadCount > 100) { // Adjust threshold based on your application
System.err.printf("High thread count: %d (peak: %d)%n", threadCount, peakThreadCount);
performanceMonitor.recordEvent("HIGH_THREAD_COUNT",
Map.of("currentThreads", String.valueOf(threadCount),
"peakThreads", String.valueOf(peakThreadCount)));
}
}
private void checkAgentPerformance() {
// Monitor agent-specific performance metrics
long startTime = System.currentTimeMillis();
// Perform a quick agent operation to measure performance
performanceMonitor.sampleOperation();
long endTime = System.currentTimeMillis();
long duration = endTime - startTime;
if (duration > 100) { // 100ms threshold
System.err.printf("Slow agent operation: %d ms%n", duration);
performanceMonitor.recordEvent("SLOW_AGENT_OPERATION",
Map.of("durationMs", String.valueOf(duration)));
}
}
public void stop() {
scheduler.shutdown();
try {
if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) {
scheduler.shutdownNow();
}
} catch (InterruptedException e) {
scheduler.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
Advanced Configuration & Management
Dynamic Configuration Management
package com.contrast.security.management;
import com.contrastsecurity.config.DynamicConfig;
import com.contrastsecurity.config.ConfigManager;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class DynamicConfigurationManager {
private final ConfigManager configManager;
private final ScheduledExecutorService configUpdater;
public DynamicConfigurationManager() {
this.configManager = ConfigManager.getInstance();
this.configUpdater = Executors.newScheduledThreadPool(1);
startConfigurationUpdates();
}
private void startConfigurationUpdates() {
// Check for configuration updates every 5 minutes
configUpdater.scheduleAtFixedRate(this::updateConfiguration, 0, 5, TimeUnit.MINUTES);
}
private void updateConfiguration() {
try {
DynamicConfig newConfig = fetchLatestConfiguration();
if (newConfig != null && hasConfigurationChanged(newConfig)) {
applyNewConfiguration(newConfig);
System.out.println("Contrast Agent configuration updated successfully");
}
} catch (Exception e) {
System.err.println("Failed to update configuration: " + e.getMessage());
}
}
private DynamicConfig fetchLatestConfiguration() {
// Implementation to fetch configuration from:
// - Contrast Platform API
// - Configuration server
// - Database
// - File system
// Example: Fetch from Contrast Platform
return configManager.fetchConfigFromPlatform();
}
private boolean hasConfigurationChanged(DynamicConfig newConfig) {
DynamicConfig currentConfig = configManager.getCurrentConfig();
return !currentConfig.equals(newConfig);
}
private void applyNewConfiguration(DynamicConfig newConfig) {
configManager.applyConfiguration(newConfig);
// Log configuration changes
logConfigurationChange(newConfig);
}
private void logConfigurationChange(DynamicConfig config) {
System.out.println("Applied new security configuration:");
System.out.println(" Protection Enabled: " + config.isProtectionEnabled());
System.out.println(" Assessment Enabled: " + config.isAssessmentEnabled());
System.out.println(" Log Level: " + config.getLogLevel());
// Log other relevant configuration changes
}
public void updateRuleStatus(String ruleId, boolean enabled) {
try {
configManager.updateRuleStatus(ruleId, enabled);
System.out.printf("Rule %s %s%n", ruleId, enabled ? "enabled" : "disabled");
} catch (Exception e) {
System.err.println("Failed to update rule status: " + e.getMessage());
}
}
public void setProtectionMode(boolean enabled) {
try {
configManager.setProtectionEnabled(enabled);
System.out.println("Protection mode " + (enabled ? "enabled" : "disabled"));
} catch (Exception e) {
System.err.println("Failed to update protection mode: " + e.getMessage());
}
}
public void shutdown() {
configUpdater.shutdown();
try {
if (!configUpdater.awaitTermination(10, TimeUnit.SECONDS)) {
configUpdater.shutdownNow();
}
} catch (InterruptedException e) {
configUpdater.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
Best Practices
1. Agent Deployment
package com.contrast.security.bestpractices;
public class AgentDeploymentGuide {
/*
* Best Practices for Contrast Agent Deployment:
*
* 1. Environment-Specific Configuration:
* - Use different application names for dev/staging/prod
* - Configure appropriate log levels per environment
* - Set up environment-specific security policies
*
* 2. Performance Considerations:
* - Monitor agent memory and CPU usage
* - Use appropriate instrumentation filters
* - Configure sampling for high-traffic applications
*
* 3. Security Configuration:
* - Enable protection in production
* - Configure appropriate blocking rules
* - Set up alerting for critical events
*
* 4. Maintenance:
* - Keep agent updated to latest version
* - Regularly review security events
* - Update custom rules as needed
*
* 5. Integration:
* - Integrate with existing monitoring systems
* - Set up centralized logging
* - Configure alert escalation procedures
*/
}
2. Troubleshooting Common Issues
package com.contrast.security.troubleshooting;
public class AgentTroubleshooter {
/*
* Common Issues and Solutions:
*
* 1. Agent Not Starting:
* - Check JVM arguments
* - Verify Contrast connection settings
* - Check network connectivity to Contrast platform
*
* 2. High Memory Usage:
* - Adjust instrumentation filters
* - Increase JVM heap size if necessary
* - Review event sampling configuration
*
* 3. Performance Impact:
* - Use performance monitoring
* - Adjust protection rules
* - Consider using assess mode only in development
*
* 4. False Positives:
* - Tune custom rules
* - Use whitelisting for known safe patterns
* - Adjust rule sensitivity
*
* 5. Connection Issues:
* - Verify API keys and service keys
* - Check proxy settings if behind corporate firewall
* - Verify Contrast platform status
*/
}
This comprehensive Contrast Security Agent implementation provides enterprise-grade application security monitoring, vulnerability detection, and real-time attack protection for Java applications. The agent integrates seamlessly with existing applications and provides detailed security insights without requiring code changes.