Sqreen, now part of Datadog, provides Runtime Application Self-Protection (RASP) and application security monitoring. This comprehensive guide covers Java integration for real-time threat detection, security monitoring, and automated protection.
Understanding Sqreen/Datadog Application Security
Key Security Features:
- RASP (Runtime Application Self-Protection): Real-time attack detection and blocking
- Application Security Monitoring: Continuous security observability
- Threat Intelligence: Leverages Datadog's global threat intelligence
- Automated Protection: Blocks attacks without manual intervention
- Security Analytics: Correlates application security with performance data
Java Dependencies Setup
<dependencies> <!-- Sqreen Agent (usually loaded via -javaagent) --> <!-- Datadog Java Tracer (includes security features) --> <dependency> <groupId>com.datadoghq</groupId> <artifactId>dd-trace-api</artifactId> <version>1.10.0</version> </dependency> <!-- Spring Boot Security Integration --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <!-- Web application security --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> </dependency> <!-- JSON processing --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.16.1</version> </dependency> <!-- HTTP client for Datadog API --> <dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> <version>4.12.0</version> </dependency> <!-- Logging integration --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </dependency> </dependencies>
Security Configuration Models
package com.example.sqreen.security; import com.fasterxml.jackson.annotation.JsonInclude; import java.util.*; @JsonInclude(JsonInclude.Include.NON_NULL) public class SecurityEvent { private String eventId; private EventType eventType; private Date timestamp; private String sessionId; private String userId; private String ipAddress; private String userAgent; private Map<String, Object> context; private Map<String, Object> requestData; private Map<String, Object> responseData; private ThreatLevel threatLevel; private boolean blocked; private String ruleName; private String applicationId; public enum EventType { SQL_INJECTION, XSS, PATH_TRAVERSAL, RCE_ATTEMPT, AUTH_BYPASS, RATE_LIMIT, SUSPICIOUS_ACTIVITY, LOGIN_ATTEMPT, DATA_ACCESS, CONFIGURATION_CHANGE } public enum ThreatLevel { LOW, MEDIUM, HIGH, CRITICAL } // Constructors public SecurityEvent() { this.context = new HashMap<>(); this.requestData = new HashMap<>(); this.responseData = new HashMap<>(); this.timestamp = new Date(); } public SecurityEvent(EventType eventType, ThreatLevel threatLevel) { this(); this.eventType = eventType; this.threatLevel = threatLevel; this.eventId = UUID.randomUUID().toString(); } // Getters and setters public String getEventId() { return eventId; } public void setEventId(String eventId) { this.eventId = eventId; } public EventType getEventType() { return eventType; } public void setEventType(EventType eventType) { this.eventType = eventType; } public Date getTimestamp() { return timestamp; } public void setTimestamp(Date timestamp) { this.timestamp = timestamp; } public String getSessionId() { return sessionId; } public void setSessionId(String sessionId) { this.sessionId = sessionId; } public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public String getIpAddress() { return ipAddress; } public void setIpAddress(String ipAddress) { this.ipAddress = ipAddress; } public String getUserAgent() { return userAgent; } public void setUserAgent(String userAgent) { this.userAgent = userAgent; } public Map<String, Object> getContext() { return context; } public void setContext(Map<String, Object> context) { this.context = context; } public Map<String, Object> getRequestData() { return requestData; } public void setRequestData(Map<String, Object> requestData) { this.requestData = requestData; } public Map<String, Object> getResponseData() { return responseData; } public void setResponseData(Map<String, Object> responseData) { this.responseData = responseData; } public ThreatLevel getThreatLevel() { return threatLevel; } public void setThreatLevel(ThreatLevel threatLevel) { this.threatLevel = threatLevel; } public boolean isBlocked() { return blocked; } public void setBlocked(boolean blocked) { this.blocked = blocked; } public String getRuleName() { return ruleName; } public void setRuleName(String ruleName) { this.ruleName = ruleName; } public String getApplicationId() { return applicationId; } public void setApplicationId(String applicationId) { this.applicationId = applicationId; } // Builder methods public SecurityEvent withContext(String key, Object value) { this.context.put(key, value); return this; } public SecurityEvent withRequestData(String key, Object value) { this.requestData.put(key, value); return this; } } @JsonInclude(JsonInclude.Include.NON_NULL) public class SecurityRule { private String name; private RuleType type; private String description; private Map<String, Object> conditions; private RuleAction action; private boolean enabled; private int priority; private Date createdAt; private Date updatedAt; public enum RuleType { RATE_LIMIT, PATTERN_MATCH, BEHAVIORAL, GEO_LOCATION, USER_AGENT, IP_REPUTATION } public enum RuleAction { BLOCK, ALERT, CAPTCHA, THROTTLE, LOG } // Constructors public SecurityRule() { this.conditions = new HashMap<>(); this.enabled = true; this.priority = 1; this.createdAt = new Date(); } public SecurityRule(String name, RuleType type) { this(); this.name = name; this.type = type; } // Getters and setters public String getName() { return name; } public void setName(String name) { this.name = name; } public RuleType getType() { return type; } public void setType(RuleType type) { this.type = type; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public Map<String, Object> getConditions() { return conditions; } public void setConditions(Map<String, Object> conditions) { this.conditions = conditions; } public RuleAction getAction() { return action; } public void setAction(RuleAction action) { this.action = action; } public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } public int getPriority() { return priority; } public void setPriority(int priority) { this.priority = priority; } public Date getCreatedAt() { return createdAt; } public void setCreatedAt(Date createdAt) { this.createdAt = createdAt; } public Date getUpdatedAt() { return updatedAt; } public void setUpdatedAt(Date updatedAt) { this.updatedAt = updatedAt; } // Builder methods public SecurityRule withCondition(String key, Object value) { this.conditions.put(key, value); return this; } } @JsonInclude(JsonInclude.Include.NON_NULL) public class SecurityMetrics { private Date timestamp; private String applicationId; private Map<String, Long> eventCounts; private Map<String, Long> blockedCounts; private Map<SecurityEvent.ThreatLevel, Long> threatLevelCounts; private long totalRequests; private long maliciousRequests; private double securityScore; // Constructors public SecurityMetrics() { this.timestamp = new Date(); this.eventCounts = new HashMap<>(); this.blockedCounts = new HashMap<>(); this.threatLevelCounts = new HashMap<>(); } // Getters and setters public Date getTimestamp() { return timestamp; } public void setTimestamp(Date timestamp) { this.timestamp = timestamp; } public String getApplicationId() { return applicationId; } public void setApplicationId(String applicationId) { this.applicationId = applicationId; } public Map<String, Long> getEventCounts() { return eventCounts; } public void setEventCounts(Map<String, Long> eventCounts) { this.eventCounts = eventCounts; } public Map<String, Long> getBlockedCounts() { return blockedCounts; } public void setBlockedCounts(Map<String, Long> blockedCounts) { this.blockedCounts = blockedCounts; } public Map<SecurityEvent.ThreatLevel, Long> getThreatLevelCounts() { return threatLevelCounts; } public void setThreatLevelCounts(Map<SecurityEvent.ThreatLevel, Long> threatLevelCounts) { this.threatLevelCounts = threatLevelCounts; } public long getTotalRequests() { return totalRequests; } public void setTotalRequests(long totalRequests) { this.totalRequests = totalRequests; } public long getMaliciousRequests() { return maliciousRequests; } public void setMaliciousRequests(long maliciousRequests) { this.maliciousRequests = maliciousRequests; } public double getSecurityScore() { return securityScore; } public void setSecurityScore(double securityScore) { this.securityScore = securityScore; } } Sqreen/Datadog Security Manager
package com.example.sqreen.security; import com.fasterxml.jackson.databind.ObjectMapper; import okhttp3.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.core.context.SecurityContextHolder; import java.io.IOException; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class SqreenSecurityManager { private static final Logger logger = LoggerFactory.getLogger(SqreenSecurityManager.class); private final ObjectMapper objectMapper; private final OkHttpClient httpClient; private final String datadogApiKey; private final String datadogSite; private final String applicationId; // In-memory storage for demo (use Redis in production) private final Map<String, UserSecurityContext> userContexts; private final Map<String, Integer> ipRequestCounts; private final List<SecurityRule> securityRules; private final ScheduledExecutorService scheduler; public SqreenSecurityManager(String datadogApiKey, String datadogSite, String applicationId) { this.objectMapper = new ObjectMapper(); this.httpClient = new OkHttpClient(); this.datadogApiKey = datadogApiKey; this.datadogSite = datadogSite; this.applicationId = applicationId; this.userContexts = new ConcurrentHashMap<>(); this.ipRequestCounts = new ConcurrentHashMap<>(); this.securityRules = new ArrayList<>(); this.scheduler = Executors.newScheduledThreadPool(2); initializeDefaultRules(); startMetricsCollection(); } /** * Track security event */ public void trackSecurityEvent(SecurityEvent event) { try { event.setApplicationId(applicationId); // Apply security rules applySecurityRules(event); // Log event locally logger.warn("Security Event: {} - {} - {}", event.getEventType(), event.getThreatLevel(), event.getRuleName()); // Send to Datadog sendToDatadog(event); // Update user context if (event.getUserId() != null) { updateUserSecurityContext(event); } } catch (Exception e) { logger.error("Failed to track security event", e); } } /** * Check request for security violations */ public SecurityCheckResult checkRequest(HttpServletRequest request) { SecurityCheckResult result = new SecurityCheckResult(); result.setRequestId(UUID.randomUUID().toString()); result.setTimestamp(new Date()); try { String ipAddress = getClientIpAddress(request); String userAgent = request.getHeader("User-Agent"); String sessionId = request.getSession().getId(); // Check rate limiting if (isRateLimited(ipAddress)) { result.setBlocked(true); result.setBlockReason("Rate limit exceeded"); SecurityEvent rateLimitEvent = new SecurityEvent( SecurityEvent.EventType.RATE_LIMIT, SecurityEvent.ThreatLevel.MEDIUM ); rateLimitEvent.setIpAddress(ipAddress); rateLimitEvent.setUserAgent(userAgent); rateLimitEvent.setBlocked(true); rateLimitEvent.setRuleName("rate-limit-global"); trackSecurityEvent(rateLimitEvent); return result; } // Check for suspicious patterns checkSuspiciousPatterns(request, result); // Check user agent checkUserAgent(userAgent, result); // Update metrics updateRequestMetrics(ipAddress); } catch (Exception e) { logger.error("Error during security check", e); } return result; } /** * Identify user for security tracking */ public void identifyUser(String userId, Map<String, Object> traits) { try { UserSecurityContext context = userContexts.computeIfAbsent(userId, k -> new UserSecurityContext(userId)); context.setTraits(traits); context.setLastSeen(new Date()); // Track identification event SecurityEvent identifyEvent = new SecurityEvent( SecurityEvent.EventType.SUSPICIOUS_ACTIVITY, SecurityEvent.ThreatLevel.LOW ); identifyEvent.setUserId(userId); identifyEvent.withContext("traits", traits); trackSecurityEvent(identifyEvent); } catch (Exception e) { logger.error("Failed to identify user", e); } } /** * Track authentication events */ public void trackAuthEvent(String userId, boolean success, String method, Map<String, Object> context) { SecurityEvent authEvent = new SecurityEvent( SecurityEvent.EventType.LOGIN_ATTEMPT, success ? SecurityEvent.ThreatLevel.LOW : SecurityEvent.ThreatLevel.MEDIUM ); authEvent.setUserId(userId); authEvent.setBlocked(!success); authEvent.withContext("auth_method", method); authEvent.withContext("success", success); if (context != null) { authEvent.getContext().putAll(context); } trackSecurityEvent(authEvent); // Update user context if (success && userId != null) { UserSecurityContext userContext = userContexts.computeIfAbsent(userId, k -> new UserSecurityContext(userId)); userContext.setLastLogin(new Date()); userContext.setFailedLoginAttempts(0); } else if (userId != null) { UserSecurityContext userContext = userContexts.get(userId); if (userContext != null) { userContext.incrementFailedAttempts(); } } } private void applySecurityRules(SecurityEvent event) { for (SecurityRule rule : securityRules) { if (!rule.isEnabled()) continue; if (evaluateRule(rule, event)) { event.setRuleName(rule.getName()); switch (rule.getAction()) { case BLOCK: event.setBlocked(true); break; case ALERT: // Send alert (could integrate with PagerDuty, Slack, etc.) sendSecurityAlert(event, rule); break; case THROTTLE: // Implement throttling logic break; default: // Just log break; } // Stop at first matching rule (based on priority) break; } } } private boolean evaluateRule(SecurityRule rule, SecurityEvent event) { switch (rule.getType()) { case RATE_LIMIT: return evaluateRateLimitRule(rule, event); case PATTERN_MATCH: return evaluatePatternRule(rule, event); case BEHAVIORAL: return evaluateBehavioralRule(rule, event); default: return false; } } private boolean evaluateRateLimitRule(SecurityRule rule, SecurityEvent event) { // Implement rate limiting logic String ip = event.getIpAddress(); if (ip != null) { int count = ipRequestCounts.getOrDefault(ip, 0); int limit = (Integer) rule.getConditions().getOrDefault("limit", 100); return count > limit; } return false; } private boolean evaluatePatternRule(SecurityRule rule, SecurityEvent event) { // Implement pattern matching logic return false; } private boolean evaluateBehavioralRule(SecurityRule rule, SecurityEvent event) { // Implement behavioral analysis return false; } private boolean isRateLimited(String ipAddress) { int count = ipRequestCounts.getOrDefault(ipAddress, 0); return count > 1000; // Example limit } private void checkSuspiciousPatterns(HttpServletRequest request, SecurityCheckResult result) { // Check for SQL injection patterns Enumeration<String> paramNames = request.getParameterNames(); while (paramNames.hasMoreElements()) { String paramName = paramNames.nextElement(); String paramValue = request.getParameter(paramName); if (containsSqlInjectionPattern(paramValue)) { result.setBlocked(true); result.setBlockReason("SQL injection attempt detected"); SecurityEvent sqlEvent = new SecurityEvent( SecurityEvent.EventType.SQL_INJECTION, SecurityEvent.ThreatLevel.HIGH ); sqlEvent.setIpAddress(getClientIpAddress(request)); sqlEvent.setBlocked(true); sqlEvent.withRequestData("parameter", paramName); sqlEvent.withRequestData("value", maskSensitiveData(paramValue)); trackSecurityEvent(sqlEvent); break; } } } private void checkUserAgent(String userAgent, SecurityCheckResult result) { if (userAgent == null) return; List<String> suspiciousAgents = Arrays.asList( "sqlmap", "nikto", "metasploit", "nmap" ); for (String suspicious : suspiciousAgents) { if (userAgent.toLowerCase().contains(suspicious)) { result.setBlocked(true); result.setBlockReason("Suspicious user agent detected"); break; } } } private boolean containsSqlInjectionPattern(String value) { if (value == null) return false; String[] patterns = { "';", "--", "/*", "*/", "xp_", "union select", "or 1=1", "and 1=1" }; String lowerValue = value.toLowerCase(); for (String pattern : patterns) { if (lowerValue.contains(pattern)) { return true; } } return false; } private void updateRequestMetrics(String ipAddress) { ipRequestCounts.merge(ipAddress, 1, Integer::sum); } private void updateUserSecurityContext(SecurityEvent event) { UserSecurityContext context = userContexts.computeIfAbsent(event.getUserId(), k -> new UserSecurityContext(event.getUserId())); context.getSecurityEvents().add(event); context.setLastActivity(new Date()); if (event.getThreatLevel() == SecurityEvent.ThreatLevel.HIGH || event.getThreatLevel() == SecurityEvent.ThreatLevel.CRITICAL) { context.incrementHighSeverityEvents(); } } private void sendToDatadog(SecurityEvent event) throws IOException { // Convert event to Datadog log format Map<String, Object> logEntry = new HashMap<>(); logEntry.put("ddsource", "sqreen-java"); logEntry.put("ddtags", "env:production,version:1.0"); logEntry.put("hostname", System.getenv("HOSTNAME")); logEntry.put("service", applicationId); logEntry.put("message", event); String jsonBody = objectMapper.writeValueAsString(logEntry); Request request = new Request.Builder() .url("https://http-intake.logs." + datadogSite + "/api/v2/logs") .post(RequestBody.create(jsonBody, MediaType.parse("application/json"))) .header("DD-API-KEY", datadogApiKey) .header("Content-Type", "application/json") .build(); // Fire and forget - don't block application httpClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { logger.warn("Failed to send security event to Datadog", e); } @Override public void onResponse(Call call, Response response) { if (!response.isSuccessful()) { logger.warn("Datadog API returned error: {}", response.code()); } response.close(); } }); } private void sendSecurityAlert(SecurityEvent event, SecurityRule rule) { // Implement alerting logic (Slack, PagerDuty, etc.) logger.error("SECURITY ALERT - Rule: {}, Event: {}, Threat: {}", rule.getName(), event.getEventType(), event.getThreatLevel()); } private void initializeDefaultRules() { // Rate limiting rule SecurityRule rateLimitRule = new SecurityRule("rate-limit-global", SecurityRule.RuleType.RATE_LIMIT); rateLimitRule.setDescription("Global rate limiting"); rateLimitRule.setAction(SecurityRule.RuleAction.BLOCK); rateLimitRule.withCondition("limit", 1000); rateLimitRule.withCondition("window_seconds", 60); securityRules.add(rateLimitRule); // SQL injection rule SecurityRule sqlInjectionRule = new SecurityRule("sql-injection-detection", SecurityRule.RuleType.PATTERN_MATCH); sqlInjectionRule.setDescription("SQL injection pattern detection"); sqlInjectionRule.setAction(SecurityRule.RuleAction.BLOCK); sqlInjectionRule.withCondition("patterns", Arrays.asList("';", "union select", "or 1=1")); securityRules.add(sqlInjectionRule); // Behavioral rule for failed logins SecurityRule failedLoginRule = new SecurityRule("failed-login-threshold", SecurityRule.RuleType.BEHAVIORAL); failedLoginRule.setDescription("Multiple failed login attempts"); failedLoginRule.setAction(SecurityRule.RuleAction.ALERT); failedLoginRule.withCondition("threshold", 5); failedLoginRule.withCondition("window_minutes", 10); securityRules.add(failedLoginRule); } private void startMetricsCollection() { scheduler.scheduleAtFixedRate(this::collectMetrics, 0, 1, TimeUnit.MINUTES); scheduler.scheduleAtFixedRate(this::cleanupOldData, 0, 5, TimeUnit.MINUTES); } private void collectMetrics() { try { SecurityMetrics metrics = new SecurityMetrics(); metrics.setApplicationId(applicationId); // Calculate metrics from recent events // This would aggregate data from your event storage // Send metrics to Datadog sendMetricsToDatadog(metrics); } catch (Exception e) { logger.error("Failed to collect metrics", e); } } private void cleanupOldData() { // Clean up old IP counts // Clean up old user contexts } private void sendMetricsToDatadog(SecurityMetrics metrics) { // Implement metrics sending to Datadog } private String getClientIpAddress(HttpServletRequest request) { String xForwardedFor = request.getHeader("X-Forwarded-For"); if (xForwardedFor != null && !xForwardedFor.isEmpty()) { return xForwardedFor.split(",")[0].trim(); } return request.getRemoteAddr(); } private String maskSensitiveData(String data) { if (data == null || data.length() < 8) return "***"; return data.substring(0, 4) + "***" + data.substring(data.length() - 4); } public static class SecurityCheckResult { private String requestId; private Date timestamp; private boolean blocked; private String blockReason; private Map<String, Object> details; public SecurityCheckResult() { this.details = new HashMap<>(); } // Getters and setters public String getRequestId() { return requestId; } public void setRequestId(String requestId) { this.requestId = requestId; } public Date getTimestamp() { return timestamp; } public void setTimestamp(Date timestamp) { this.timestamp = timestamp; } public boolean isBlocked() { return blocked; } public void setBlocked(boolean blocked) { this.blocked = blocked; } public String getBlockReason() { return blockReason; } public void setBlockReason(String blockReason) { this.blockReason = blockReason; } public Map<String, Object> getDetails() { return details; } public void setDetails(Map<String, Object> details) { this.details = details; } } public static class UserSecurityContext { private String userId; private Date lastSeen; private Date lastLogin; private int failedLoginAttempts; private int highSeverityEvents; private Map<String, Object> traits; private List<SecurityEvent> securityEvents; public UserSecurityContext(String userId) { this.userId = userId; this.traits = new HashMap<>(); this.securityEvents = new ArrayList<>(); this.lastSeen = new Date(); } // Getters and setters public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public Date getLastSeen() { return lastSeen; } public void setLastSeen(Date lastSeen) { this.lastSeen = lastSeen; } public Date getLastLogin() { return lastLogin; } public void setLastLogin(Date lastLogin) { this.lastLogin = lastLogin; } public int getFailedLoginAttempts() { return failedLoginAttempts; } public void setFailedLoginAttempts(int failedLoginAttempts) { this.failedLoginAttempts = failedLoginAttempts; } public int getHighSeverityEvents() { return highSeverityEvents; } public void setHighSeverityEvents(int highSeverityEvents) { this.highSeverityEvents = highSeverityEvents; } public Map<String, Object> getTraits() { return traits; } public void setTraits(Map<String, Object> traits) { this.traits = traits; } public List<SecurityEvent> getSecurityEvents() { return securityEvents; } public void setSecurityEvents(List<SecurityEvent> securityEvents) { this.securityEvents = securityEvents; } public void incrementFailedAttempts() { this.failedLoginAttempts++; } public void incrementHighSeverityEvents() { this.highSeverityEvents++; } } } Spring Boot Integration
package com.example.sqreen.security; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.HashMap; import java.util.Map; @Component public class SecurityMonitoringInterceptor implements HandlerInterceptor { private final SqreenSecurityManager securityManager; public SecurityMonitoringInterceptor(SqreenSecurityManager securityManager) { this.securityManager = securityManager; } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // Perform security check SqreenSecurityManager.SecurityCheckResult checkResult = securityManager.checkRequest(request); if (checkResult.isBlocked()) { response.setStatus(429); // Too Many Requests or appropriate status response.getWriter().write("Request blocked for security reasons"); return false; } // Add security headers addSecurityHeaders(response); return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // Track request completion if (ex != null) { SecurityEvent errorEvent = new SecurityEvent( SecurityEvent.EventType.SUSPICIOUS_ACTIVITY, SecurityEvent.ThreatLevel.MEDIUM ); errorEvent.setIpAddress(getClientIpAddress(request)); errorEvent.withContext("exception", ex.getMessage()); errorEvent.withContext("status_code", response.getStatus()); securityManager.trackSecurityEvent(errorEvent); } // Identify user if authenticated identifyAuthenticatedUser(request); } private void addSecurityHeaders(HttpServletResponse response) { response.setHeader("X-Content-Type-Options", "nosniff"); response.setHeader("X-Frame-Options", "DENY"); response.setHeader("X-XSS-Protection", "1; mode=block"); response.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains"); } private void identifyAuthenticatedUser(HttpServletRequest request) { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication != null && authentication.isAuthenticated() && authentication.getPrincipal() instanceof UserDetails) { UserDetails userDetails = (UserDetails) authentication.getPrincipal(); Map<String, Object> traits = new HashMap<>(); traits.put("username", userDetails.getUsername()); traits.put("authorities", userDetails.getAuthorities()); securityManager.identifyUser(userDetails.getUsername(), traits); } } private String getClientIpAddress(HttpServletRequest request) { String xForwardedFor = request.getHeader("X-Forwarded-For"); if (xForwardedFor != null && !xForwardedFor.isEmpty()) { return xForwardedFor.split(",")[0].trim(); } return request.getRemoteAddr(); } } Spring Security Integration
package com.example.sqreen.security; import org.springframework.security.authentication.event.*; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; import java.util.HashMap; import java.util.Map; @Component public class SpringSecurityEventListener { private final SqreenSecurityManager securityManager; public SpringSecurityEventListener(SqreenSecurityManager securityManager) { this.securityManager = securityManager; } @EventListener public void handleAuthenticationSuccess(AuthenticationSuccessEvent event) { String username = event.getAuthentication().getName(); Map<String, Object> context = new HashMap<>(); context.put("authentication_type", event.getAuthentication().getClass().getSimpleName()); securityManager.trackAuthEvent(username, true, "spring_security", context); } @EventListener public void handleAuthenticationFailure(AbstractAuthenticationFailureEvent event) { String username = event.getAuthentication().getName(); Map<String, Object> context = new HashMap<>(); context.put("failure_type", event.getException().getClass().getSimpleName()); context.put("failure_message", event.getException().getMessage()); securityManager.trackAuthEvent(username, false, "spring_security", context); } @EventListener public void handleAuthorizationEvent(AuthorizationEvent event) { // Track authorization decisions SecurityEvent authEvent = new SecurityEvent( SecurityEvent.EventType.AUTH_BYPASS, SecurityEvent.ThreatLevel.MEDIUM ); // Add authorization context securityManager.trackSecurityEvent(authEvent); } } REST Controller for Security Management
package com.example.sqreen.security; import org.springframework.web.bind.annotation.*; import org.springframework.http.ResponseEntity; import javax.servlet.http.HttpServletRequest; import java.util.*; @RestController @RequestMapping("/api/security") public class SecurityController { private final SqreenSecurityManager securityManager; public SecurityController(SqreenSecurityManager securityManager) { this.securityManager = securityManager; } @PostMapping("/track") public ResponseEntity<Map<String, Object>> trackSecurityEvent( @RequestBody SecurityEvent event) { securityManager.trackSecurityEvent(event); return ResponseEntity.ok(Map.of( "success", true, "message", "Security event tracked" )); } @PostMapping("/identify") public ResponseEntity<Map<String, Object>> identifyUser( @RequestBody IdentifyUserRequest request) { securityManager.identifyUser(request.getUserId(), request.getTraits()); return ResponseEntity.ok(Map.of( "success", true, "message", "User identified" )); } @GetMapping("/metrics") public ResponseEntity<SecurityMetrics> getSecurityMetrics() { // Return current security metrics SecurityMetrics metrics = new SecurityMetrics(); // Populate with actual metrics return ResponseEntity.ok(metrics); } @PostMapping("/test/sql-injection") public ResponseEntity<Map<String, Object>> testSqlInjectionDetection( HttpServletRequest request) { // This endpoint simulates SQL injection for testing String testParam = request.getParameter("test"); SecurityEvent testEvent = new SecurityEvent( SecurityEvent.EventType.SQL_INJECTION, SecurityEvent.ThreatLevel.HIGH ); testEvent.setIpAddress(getClientIpAddress(request)); testEvent.withRequestData("test_parameter", testParam); securityManager.trackSecurityEvent(testEvent); return ResponseEntity.ok(Map.of( "success", true, "message", "SQL injection test completed" )); } private String getClientIpAddress(HttpServletRequest request) { String xForwardedFor = request.getHeader("X-Forwarded-For"); if (xForwardedFor != null && !xForwardedFor.isEmpty()) { return xForwardedFor.split(",")[0].trim(); } return request.getRemoteAddr(); } // Request DTOs public static class IdentifyUserRequest { private String userId; private Map<String, Object> traits; // Getters and setters public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public Map<String, Object> getTraits() { return traits; } public void setTraits(Map<String, Object> traits) { this.traits = traits; } } } Configuration Class
package com.example.sqreen.security; import org.springframework.beans.factory.annotation.Value; 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; @Configuration public class SecurityConfig implements WebMvcConfigurer { @Value("${datadog.api.key:}") private String datadogApiKey; @Value("${datadog.site:datadoghq.com}") private String datadogSite; @Value("${application.id:my-spring-app}") private String applicationId; @Bean public SqreenSecurityManager sqreenSecurityManager() { return new SqreenSecurityManager(datadogApiKey, datadogSite, applicationId); } @Bean public SecurityMonitoringInterceptor securityMonitoringInterceptor() { return new SecurityMonitoringInterceptor(sqreenSecurityManager()); } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(securityMonitoringInterceptor()) .addPathPatterns("/**") .excludePathPatterns("/health", "/metrics"); } } Best Practices for Production
- Proper Agent Configuration: Use Sqreen agent with
-javaagentJVM parameter - Data Sampling: Implement sampling for high-traffic applications
- Sensitive Data Masking: Never log sensitive information
- Performance Monitoring: Monitor the impact of security checks
- Alert Tuning: Fine-tune alerts to reduce false positives
- Compliance: Ensure compliance with data protection regulations
- Incident Response: Integrate with your incident response procedures
- Regular Updates: Keep dependencies and security rules updated
Conclusion
Implementing Sqreen/Datadog security in Java provides comprehensive runtime protection and security monitoring. The Java-based approach offers:
- Real-time Threat Detection: Immediate identification of security threats
- Behavioral Analysis: Detection of anomalous user behavior
- Integration with Spring Security: Seamless authentication and authorization monitoring
- Datadog Integration: Centralized security observability
- Custom Security Rules: Tailored protection for your application
- Comprehensive Metrics: Security posture assessment and reporting
By integrating these security measures, you can significantly enhance your application's security posture, detect threats in real-time, and maintain comprehensive security observability through the Datadog platform.