1. Core Signal Sciences Client
// SignalSciencesClient.java
package com.signalsciences;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.util.*;
public class SignalSciencesClient {
private final String baseUrl;
private final String email;
private final String apiToken;
private final String corpName;
private final CloseableHttpClient httpClient;
private final ObjectMapper objectMapper;
public SignalSciencesClient(String baseUrl, String email, String apiToken, String corpName) {
this.baseUrl = baseUrl;
this.email = email;
this.apiToken = apiToken;
this.corpName = corpName;
this.httpClient = HttpClients.createDefault();
this.objectMapper = new ObjectMapper();
}
// Corporation Management
public List<Corporation> getCorporations() throws SignalSciencesException {
return executeGet("/v0/corps",
objectMapper.getTypeFactory().constructCollectionType(List.class, Corporation.class));
}
public Corporation getCorporation(String corpName) throws SignalSciencesException {
return executeGet("/v0/corps/" + corpName, Corporation.class);
}
// Site Management
public List<Site> getSites() throws SignalSciencesException {
return executeGet("/v0/corps/" + corpName + "/sites",
objectMapper.getTypeFactory().constructCollectionType(List.class, Site.class));
}
public Site getSite(String siteName) throws SignalSciencesException {
return executeGet("/v0/corps/" + corpName + "/sites/" + siteName, Site.class);
}
public Site createSite(SiteRequest siteRequest) throws SignalSciencesException {
return executePost("/v0/corps/" + corpName + "/sites", siteRequest, Site.class);
}
// Threat Intelligence
public List<Threat> getRecentThreats(String siteName, Integer limit) throws SignalSciencesException {
String url = "/v0/corps/" + corpName + "/sites/" + siteName + "/threats";
if (limit != null) {
url += "?limit=" + limit;
}
return executeGet(url,
objectMapper.getTypeFactory().constructCollectionType(List.class, Threat.class));
}
public ThreatFeed getThreatFeed(String siteName) throws SignalSciencesException {
return executeGet("/v0/corps/" + corpName + "/sites/" + siteName + "/feed/threats", ThreatFeed.class);
}
// Requests and Analytics
public RequestAnalytics getRequestAnalytics(String siteName, AnalyticsQuery query)
throws SignalSciencesException {
String url = buildAnalyticsUrl("/v0/corps/" + corpName + "/sites/" + siteName + "/requests", query);
return executeGet(url, RequestAnalytics.class);
}
public TimeseriesData getTimeseriesData(String siteName, AnalyticsQuery query)
throws SignalSciencesException {
String url = buildAnalyticsUrl("/v0/corps/" + corpName + "/sites/" + siteName + "/timeseries", query);
return executeGet(url, TimeseriesData.class);
}
// Alerts and Notifications
public List<Alert> getAlerts(String siteName, AlertQuery query) throws SignalSciencesException {
String url = buildAlertUrl("/v0/corps/" + corpName + "/sites/" + siteName + "/alerts", query);
return executeGet(url,
objectMapper.getTypeFactory().constructCollectionType(List.class, Alert.class));
}
// Custom Rules and Signals
public List<CustomRule> getCustomRules(String siteName) throws SignalSciencesException {
return executeGet("/v0/corps/" + corpName + "/sites/" + siteName + "/rules",
objectMapper.getTypeFactory().constructCollectionType(List.class, CustomRule.class));
}
public CustomRule createCustomRule(String siteName, CustomRule rule) throws SignalSciencesException {
return executePost("/v0/corps/" + corpName + "/sites/" + siteName + "/rules", rule, CustomRule.class);
}
public void deleteCustomRule(String siteName, String ruleId) throws SignalSciencesException {
executeDelete("/v0/corps/" + corpName + "/sites/" + siteName + "/rules/" + ruleId);
}
// IP Lists
public List<IPList> getIPLists(String siteName) throws SignalSciencesException {
return executeGet("/v0/corps/" + corpName + "/sites/" + siteName + "/ip-lists",
objectMapper.getTypeFactory().constructCollectionType(List.class, IPList.class));
}
public IPList createIPList(String siteName, IPList ipList) throws SignalSciencesException {
return executePost("/v0/corps/" + corpName + "/sites/" + siteName + "/ip-lists", ipList, IPList.class);
}
// Private methods for HTTP operations
private <T> T executeGet(String path, Class<T> responseType) throws SignalSciencesException {
try {
String url = baseUrl + path;
HttpGet request = new HttpGet(url);
addAuthHeaders(request);
HttpResponse response = httpClient.execute(request);
String responseBody = EntityUtils.toString(response.getEntity());
if (response.getStatusLine().getStatusCode() != 200) {
throw new SignalSciencesException("GET request failed: " + responseBody);
}
return objectMapper.readValue(responseBody, responseType);
} catch (IOException e) {
throw new SignalSciencesException("GET request failed", e);
}
}
private <T> T executeGet(String path, com.fasterxml.jackson.core.type.TypeReference<T> typeReference)
throws SignalSciencesException {
try {
String url = baseUrl + path;
HttpGet request = new HttpGet(url);
addAuthHeaders(request);
HttpResponse response = httpClient.execute(request);
String responseBody = EntityUtils.toString(response.getEntity());
if (response.getStatusLine().getStatusCode() != 200) {
throw new SignalSciencesException("GET request failed: " + responseBody);
}
return objectMapper.readValue(responseBody, typeReference);
} catch (IOException e) {
throw new SignalSciencesException("GET request failed", e);
}
}
private <T> T executePost(String path, Object requestBody, Class<T> responseType)
throws SignalSciencesException {
try {
String url = baseUrl + path;
HttpPost request = new HttpPost(url);
addAuthHeaders(request);
String jsonBody = objectMapper.writeValueAsString(requestBody);
StringEntity entity = new StringEntity(jsonBody);
request.setEntity(entity);
request.setHeader("Content-type", "application/json");
HttpResponse response = httpClient.execute(request);
String responseBody = EntityUtils.toString(response.getEntity());
if (response.getStatusLine().getStatusCode() != 200) {
throw new SignalSciencesException("POST request failed: " + responseBody);
}
return objectMapper.readValue(responseBody, responseType);
} catch (IOException e) {
throw new SignalSciencesException("POST request failed", e);
}
}
private void executeDelete(String path) throws SignalSciencesException {
try {
String url = baseUrl + path;
org.apache.http.client.methods.HttpDelete request =
new org.apache.http.client.methods.HttpDelete(url);
addAuthHeaders(request);
HttpResponse response = httpClient.execute(request);
if (response.getStatusLine().getStatusCode() != 204) {
String responseBody = EntityUtils.toString(response.getEntity());
throw new SignalSciencesException("DELETE request failed: " + responseBody);
}
} catch (IOException e) {
throw new SignalSciencesException("DELETE request failed", e);
}
}
private void addAuthHeaders(org.apache.http.client.methods.HttpRequestBase request) {
String auth = Base64.getEncoder().encodeToString((email + ":" + apiToken).getBytes());
request.setHeader("Authorization", "Basic " + auth);
}
private String buildAnalyticsUrl(String basePath, AnalyticsQuery query) {
StringBuilder url = new StringBuilder(basePath);
url.append("?from=").append(query.getFrom());
url.append("&until=").append(query.getUntil());
if (query.getInterval() != null) {
url.append("&interval=").append(query.getInterval());
}
if (query.getLimit() != null) {
url.append("&limit=").append(query.getLimit());
}
if (query.getFilters() != null && !query.getFilters().isEmpty()) {
query.getFilters().forEach((key, value) ->
url.append("&").append(key).append("=").append(value));
}
return url.toString();
}
private String buildAlertUrl(String basePath, AlertQuery query) {
StringBuilder url = new StringBuilder(basePath);
boolean hasParams = false;
if (query.getSince() != null) {
url.append("?since=").append(query.getSince());
hasParams = true;
}
if (query.getUntil() != null) {
url.append(hasParams ? "&" : "?").append("until=").append(query.getUntil());
hasParams = true;
}
if (query.getLimit() != null) {
url.append(hasParams ? "&" : "?").append("limit=").append(query.getLimit());
}
return url.toString();
}
public void close() throws IOException {
httpClient.close();
}
}
2. Data Models
// Signal Sciences Data Models
package com.signalsciences;
import java.util.*;
public class Corporation {
private String name;
private String displayName;
private Date createdAt;
private Date updatedAt;
private List<Site> sites;
// Constructors, getters, and setters
public Corporation() {}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getDisplayName() { return displayName; }
public void setDisplayName(String displayName) { this.displayName = displayName; }
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; }
public List<Site> getSites() { return sites; }
public void setSites(List<Site> sites) { this.sites = sites; }
}
public class Site {
private String name;
private String displayName;
private String agentCode;
private String agentKey;
private Date createdAt;
private Date updatedAt;
private Map<String, Object> config;
private List<CustomRule> rules;
private List<IPList> ipLists;
// Constructors, getters, and setters
public Site() {}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getDisplayName() { return displayName; }
public void setDisplayName(String displayName) { this.displayName = displayName; }
public String getAgentCode() { return agentCode; }
public void setAgentCode(String agentCode) { this.agentCode = agentCode; }
public String getAgentKey() { return agentKey; }
public void setAgentKey(String agentKey) { this.agentKey = agentKey; }
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; }
public Map<String, Object> getConfig() { return config; }
public void setConfig(Map<String, Object> config) { this.config = config; }
public List<CustomRule> getRules() { return rules; }
public void setRules(List<CustomRule> rules) { this.rules = rules; }
public List<IPList> getIpLists() { return ipLists; }
public void setIpLists(List<IPList> ipLists) { this.ipLists = ipLists; }
}
public class SiteRequest {
private String name;
private String displayName;
private Map<String, Object> config;
public SiteRequest(String name, String displayName) {
this.name = name;
this.displayName = displayName;
this.config = new HashMap<>();
}
// Getters and setters
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getDisplayName() { return displayName; }
public void setDisplayName(String displayName) { this.displayName = displayName; }
public Map<String, Object> getConfig() { return config; }
public void setConfig(Map<String, Object> config) { this.config = config; }
}
public class Threat {
private String id;
private String source;
private String type;
private String severity;
private String description;
private Date timestamp;
private String clientIP;
private String country;
private String userAgent;
private String path;
private String method;
private Map<String, String> tags;
private List<String> indicators;
// Constructors, getters, and setters
public Threat() {}
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getSource() { return source; }
public void setSource(String source) { this.source = source; }
public String getType() { return type; }
public void setType(String type) { this.type = type; }
public String getSeverity() { return severity; }
public void setSeverity(String severity) { this.severity = severity; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public Date getTimestamp() { return timestamp; }
public void setTimestamp(Date timestamp) { this.timestamp = timestamp; }
public String getClientIP() { return clientIP; }
public void setClientIP(String clientIP) { this.clientIP = clientIP; }
public String getCountry() { return country; }
public void setCountry(String country) { this.country = country; }
public String getUserAgent() { return userAgent; }
public void setUserAgent(String userAgent) { this.userAgent = userAgent; }
public String getPath() { return path; }
public void setPath(String path) { this.path = path; }
public String getMethod() { return method; }
public void setMethod(String method) { this.method = method; }
public Map<String, String> getTags() { return tags; }
public void setTags(Map<String, String> tags) { this.tags = tags; }
public List<String> getIndicators() { return indicators; }
public void setIndicators(List<String> indicators) { this.indicators = indicators; }
}
public class ThreatFeed {
private List<Threat> threats;
private Date generatedAt;
private int totalCount;
private Map<String, Integer> severityBreakdown;
// Constructors, getters, and setters
public ThreatFeed() {}
public List<Threat> getThreats() { return threats; }
public void setThreats(List<Threat> threats) { this.threats = threats; }
public Date getGeneratedAt() { return generatedAt; }
public void setGeneratedAt(Date generatedAt) { this.generatedAt = generatedAt; }
public int getTotalCount() { return totalCount; }
public void setTotalCount(int totalCount) { this.totalCount = totalCount; }
public Map<String, Integer> getSeverityBreakdown() { return severityBreakdown; }
public void setSeverityBreakdown(Map<String, Integer> severityBreakdown) { this.severityBreakdown = severityBreakdown; }
}
public class RequestAnalytics {
private Date from;
private Date until;
private int totalRequests;
private int blockedRequests;
private int allowedRequests;
private Map<String, Integer> attackTypes;
private Map<String, Integer> topIPs;
private Map<String, Integer> topPaths;
private List<RequestDetail> recentRequests;
// Constructors, getters, and setters
public RequestAnalytics() {}
public Date getFrom() { return from; }
public void setFrom(Date from) { this.from = from; }
public Date getUntil() { return until; }
public void setUntil(Date until) { this.until = until; }
public int getTotalRequests() { return totalRequests; }
public void setTotalRequests(int totalRequests) { this.totalRequests = totalRequests; }
public int getBlockedRequests() { return blockedRequests; }
public void setBlockedRequests(int blockedRequests) { this.blockedRequests = blockedRequests; }
public int getAllowedRequests() { return allowedRequests; }
public void setAllowedRequests(int allowedRequests) { this.allowedRequests = allowedRequests; }
public Map<String, Integer> getAttackTypes() { return attackTypes; }
public void setAttackTypes(Map<String, Integer> attackTypes) { this.attackTypes = attackTypes; }
public Map<String, Integer> getTopIPs() { return topIPs; }
public void setTopIPs(Map<String, Integer> topIPs) { this.topIPs = topIPs; }
public Map<String, Integer> getTopPaths() { return topPaths; }
public void setTopPaths(Map<String, Integer> topPaths) { this.topPaths = topPaths; }
public List<RequestDetail> getRecentRequests() { return recentRequests; }
public void setRecentRequests(List<RequestDetail> recentRequests) { this.recentRequests = recentRequests; }
}
public class RequestDetail {
private String id;
private Date timestamp;
private String clientIP;
private String country;
private String method;
private String path;
private String userAgent;
private String action; // ALLOW, BLOCK, RATE_LIMIT
private List<String> tags;
private Map<String, String> headers;
// Constructors, getters, and setters
public RequestDetail() {}
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public Date getTimestamp() { return timestamp; }
public void setTimestamp(Date timestamp) { this.timestamp = timestamp; }
public String getClientIP() { return clientIP; }
public void setClientIP(String clientIP) { this.clientIP = clientIP; }
public String getCountry() { return country; }
public void setCountry(String country) { this.country = country; }
public String getMethod() { return method; }
public void setMethod(String method) { this.method = method; }
public String getPath() { return path; }
public void setPath(String path) { this.path = path; }
public String getUserAgent() { return userAgent; }
public void setUserAgent(String userAgent) { this.userAgent = userAgent; }
public String getAction() { return action; }
public void setAction(String action) { this.action = action; }
public List<String> getTags() { return tags; }
public void setTags(List<String> tags) { this.tags = tags; }
public Map<String, String> getHeaders() { return headers; }
public void setHeaders(Map<String, String> headers) { this.headers = headers; }
}
public class TimeseriesData {
private Date from;
private Date until;
private String interval;
private List<DataPoint> data;
// Constructors, getters, and setters
public TimeseriesData() {}
public Date getFrom() { return from; }
public void setFrom(Date from) { this.from = from; }
public Date getUntil() { return until; }
public void setUntil(Date until) { this.until = until; }
public String getInterval() { return interval; }
public void setInterval(String interval) { this.interval = interval; }
public List<DataPoint> getData() { return data; }
public void setData(List<DataPoint> data) { this.data = data; }
}
public class DataPoint {
private Date timestamp;
private int totalRequests;
private int blockedRequests;
private int attackRequests;
private Map<String, Integer> attackBreakdown;
// Constructors, getters, and setters
public DataPoint() {}
public Date getTimestamp() { return timestamp; }
public void setTimestamp(Date timestamp) { this.timestamp = timestamp; }
public int getTotalRequests() { return totalRequests; }
public void setTotalRequests(int totalRequests) { this.totalRequests = totalRequests; }
public int getBlockedRequests() { return blockedRequests; }
public void setBlockedRequests(int blockedRequests) { this.blockedRequests = blockedRequests; }
public int getAttackRequests() { return attackRequests; }
public void setAttackRequests(int attackRequests) { this.attackRequests = attackRequests; }
public Map<String, Integer> getAttackBreakdown() { return attackBreakdown; }
public void setAttackBreakdown(Map<String, Integer> attackBreakdown) { this.attackBreakdown = attackBreakdown; }
}
public class Alert {
private String id;
private String type;
private String severity;
private String description;
private Date createdAt;
private Date resolvedAt;
private String status;
private Map<String, Object> metadata;
private List<String> affectedSites;
// Constructors, getters, and setters
public Alert() {}
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getType() { return type; }
public void setType(String type) { this.type = type; }
public String getSeverity() { return severity; }
public void setSeverity(String severity) { this.severity = severity; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public Date getCreatedAt() { return createdAt; }
public void setCreatedAt(Date createdAt) { this.createdAt = createdAt; }
public Date getResolvedAt() { return resolvedAt; }
public void setResolvedAt(Date resolvedAt) { this.resolvedAt = resolvedAt; }
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
public Map<String, Object> getMetadata() { return metadata; }
public void setMetadata(Map<String, Object> metadata) { this.metadata = metadata; }
public List<String> getAffectedSites() { return affectedSites; }
public void setAffectedSites(List<String> affectedSites) { this.affectedSites = affectedSites; }
}
public class CustomRule {
private String id;
private String name;
private String description;
private String condition;
private List<String> actions;
private List<String> tags;
private boolean enabled;
private Date createdAt;
private Date updatedAt;
// Constructors, getters, and setters
public CustomRule() {}
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public String getCondition() { return condition; }
public void setCondition(String condition) { this.condition = condition; }
public List<String> getActions() { return actions; }
public void setActions(List<String> actions) { this.actions = actions; }
public List<String> getTags() { return tags; }
public void setTags(List<String> tags) { this.tags = tags; }
public boolean isEnabled() { return enabled; }
public void setEnabled(boolean enabled) { this.enabled = enabled; }
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; }
}
public class IPList {
private String id;
private String name;
private String description;
private List<String> entries;
private String type; // WHITELIST, BLACKLIST
private Date createdAt;
private Date updatedAt;
// Constructors, getters, and setters
public IPList() {}
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public List<String> getEntries() { return entries; }
public void setEntries(List<String> entries) { this.entries = entries; }
public String getType() { return type; }
public void setType(String type) { this.type = type; }
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; }
}
// Query Models
public class AnalyticsQuery {
private Date from;
private Date until;
private String interval;
private Integer limit;
private Map<String, String> filters;
public AnalyticsQuery(Date from, Date until) {
this.from = from;
this.until = until;
this.filters = new HashMap<>();
}
// Getters and setters
public Date getFrom() { return from; }
public void setFrom(Date from) { this.from = from; }
public Date getUntil() { return until; }
public void setUntil(Date until) { this.until = until; }
public String getInterval() { return interval; }
public void setInterval(String interval) { this.interval = interval; }
public Integer getLimit() { return limit; }
public void setLimit(Integer limit) { this.limit = limit; }
public Map<String, String> getFilters() { return filters; }
public void setFilters(Map<String, String> filters) { this.filters = filters; }
public void addFilter(String key, String value) {
filters.put(key, value);
}
}
public class AlertQuery {
private Date since;
private Date until;
private Integer limit;
// Getters and setters
public Date getSince() { return since; }
public void setSince(Date since) { this.since = since; }
public Date getUntil() { return until; }
public void setUntil(Date until) { this.until = until; }
public Integer getLimit() { return limit; }
public void setLimit(Integer limit) { this.limit = limit; }
}
public class SignalSciencesException extends Exception {
public SignalSciencesException(String message) {
super(message);
}
public SignalSciencesException(String message, Throwable cause) {
super(message, cause);
}
}
3. Real-time Threat Monitoring
// ThreatMonitor.java
package com.signalsciences.monitoring;
import com.signalsciences.*;
import java.util.*;
import java.util.concurrent.*;
public class ThreatMonitor {
private final SignalSciencesClient client;
private final String siteName;
private final ScheduledExecutorService scheduler;
private final List<ThreatListener> listeners;
private final Map<String, Threat> recentThreats;
private final int maxRecentThreats;
private ScheduledFuture<?> monitoringTask;
public ThreatMonitor(SignalSciencesClient client, String siteName) {
this.client = client;
this.siteName = siteName;
this.scheduler = Executors.newScheduledThreadPool(2);
this.listeners = new CopyOnWriteArrayList<>();
this.recentThreats = new ConcurrentHashMap<>();
this.maxRecentThreats = 1000;
}
public void startMonitoring(long intervalSeconds) {
if (monitoringTask != null && !monitoringTask.isCancelled()) {
throw new IllegalStateException("Monitor is already running");
}
monitoringTask = scheduler.scheduleAtFixedRate(() -> {
try {
checkForNewThreats();
} catch (Exception e) {
notifyListenersOfError(e);
}
}, 0, intervalSeconds, TimeUnit.SECONDS);
System.out.println("Started threat monitoring for site: " + siteName);
}
public void stopMonitoring() {
if (monitoringTask != null) {
monitoringTask.cancel(true);
monitoringTask = null;
}
System.out.println("Stopped threat monitoring for site: " + siteName);
}
public void addListener(ThreatListener listener) {
listeners.add(listener);
}
public void removeListener(ThreatListener listener) {
listeners.remove(listener);
}
private void checkForNewThreats() throws SignalSciencesException {
List<Threat> threats = client.getRecentThreats(siteName, 50);
for (Threat threat : threats) {
if (!recentThreats.containsKey(threat.getId())) {
recentThreats.put(threat.getId(), threat);
notifyListeners(threat);
// Maintain recent threats size
if (recentThreats.size() > maxRecentThreats) {
String oldestKey = recentThreats.keySet().iterator().next();
recentThreats.remove(oldestKey);
}
}
}
}
private void notifyListeners(Threat threat) {
for (ThreatListener listener : listeners) {
try {
listener.onThreatDetected(threat);
} catch (Exception e) {
System.err.println("Error notifying threat listener: " + e.getMessage());
}
}
}
private void notifyListenersOfError(Exception error) {
for (ThreatListener listener : listeners) {
try {
listener.onMonitoringError(error);
} catch (Exception e) {
System.err.println("Error notifying error listener: " + e.getMessage());
}
}
}
public ThreatStatistics getStatistics() {
Map<String, Integer> severityCount = new HashMap<>();
Map<String, Integer> typeCount = new HashMap<>();
Map<String, Integer> countryCount = new HashMap<>();
for (Threat threat : recentThreats.values()) {
severityCount.merge(threat.getSeverity(), 1, Integer::sum);
typeCount.merge(threat.getType(), 1, Integer::sum);
countryCount.merge(threat.getCountry(), 1, Integer::sum);
}
return new ThreatStatistics(
recentThreats.size(),
severityCount,
typeCount,
countryCount,
new Date()
);
}
public List<Threat> getRecentThreats(int limit) {
return recentThreats.values().stream()
.sorted((t1, t2) -> t2.getTimestamp().compareTo(t1.getTimestamp()))
.limit(limit)
.toList();
}
public void shutdown() {
stopMonitoring();
scheduler.shutdown();
try {
if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) {
scheduler.shutdownNow();
}
} catch (InterruptedException e) {
scheduler.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
// Threat Listener Interface
package com.signalsciences.monitoring;
import com.signalsciences.Threat;
public interface ThreatListener {
void onThreatDetected(Threat threat);
void onMonitoringError(Exception error);
}
// Threat Statistics
package com.signalsciences.monitoring;
import java.util.Date;
import java.util.Map;
public class ThreatStatistics {
private final int totalThreats;
private final Map<String, Integer> severityBreakdown;
private final Map<String, Integer> typeBreakdown;
private final Map<String, Integer> countryBreakdown;
private final Date generatedAt;
public ThreatStatistics(int totalThreats, Map<String, Integer> severityBreakdown,
Map<String, Integer> typeBreakdown, Map<String, Integer> countryBreakdown,
Date generatedAt) {
this.totalThreats = totalThreats;
this.severityBreakdown = severityBreakdown;
this.typeBreakdown = typeBreakdown;
this.countryBreakdown = countryBreakdown;
this.generatedAt = generatedAt;
}
// Getters
public int getTotalThreats() { return totalThreats; }
public Map<String, Integer> getSeverityBreakdown() { return severityBreakdown; }
public Map<String, Integer> getTypeBreakdown() { return typeBreakdown; }
public Map<String, Integer> getCountryBreakdown() { return countryBreakdown; }
public Date getGeneratedAt() { return generatedAt; }
public int getCriticalThreats() {
return severityBreakdown.getOrDefault("CRITICAL", 0) +
severityBreakdown.getOrDefault("HIGH", 0);
}
public String getTopThreatType() {
return typeBreakdown.entrySet().stream()
.max(Map.Entry.comparingByValue())
.map(Map.Entry::getKey)
.orElse("NONE");
}
public String getTopCountry() {
return countryBreakdown.entrySet().stream()
.max(Map.Entry.comparingByValue())
.map(Map.Entry::getKey)
.orElse("UNKNOWN");
}
}
4. Spring Boot Integration
// SignalSciencesConfig.java
package com.signalsciences.config;
import com.signalsciences.SignalSciencesClient;
import com.signalsciences.monitoring.ThreatMonitor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SignalSciencesConfig {
@Value("${signalsciences.baseUrl:https://dashboard.signalsciences.net}")
private String baseUrl;
@Value("${signalsciences.email}")
private String email;
@Value("${signalsciences.apiToken}")
private String apiToken;
@Value("${signalsciences.corpName}")
private String corpName;
@Value("${signalsciences.siteName}")
private String siteName;
@Value("${signalsciences.monitoring.enabled:true}")
private boolean monitoringEnabled;
@Value("${signalsciences.monitoring.interval:60}")
private long monitoringInterval;
@Bean
public SignalSciencesClient signalSciencesClient() {
return new SignalSciencesClient(baseUrl, email, apiToken, corpName);
}
@Bean
public ThreatMonitor threatMonitor(SignalSciencesClient client) {
ThreatMonitor monitor = new ThreatMonitor(client, siteName);
if (monitoringEnabled) {
monitor.startMonitoring(monitoringInterval);
// Add default listener for logging
monitor.addListener(new LoggingThreatListener());
}
return monitor;
}
}
// LoggingThreatListener.java
package com.signalsciences.config;
import com.signalsciences.Threat;
import com.signalsciences.monitoring.ThreatListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LoggingThreatListener implements ThreatListener {
private static final Logger logger = LoggerFactory.getLogger(LoggingThreatListener.class);
@Override
public void onThreatDetected(Threat threat) {
logger.warn("THREAT DETECTED - Type: {}, Severity: {}, IP: {}, Path: {}",
threat.getType(), threat.getSeverity(), threat.getClientIP(), threat.getPath());
if ("CRITICAL".equals(threat.getSeverity()) || "HIGH".equals(threat.getSeverity())) {
logger.error("CRITICAL THREAT - Immediate attention required: {}", threat.getDescription());
}
}
@Override
public void onMonitoringError(Exception error) {
logger.error("Threat monitoring error: {}", error.getMessage(), error);
}
}
// SignalSciencesController.java
package com.signalsciences.web;
import com.signalsciences.*;
import com.signalsciences.monitoring.ThreatMonitor;
import com.signalsciences.monitoring.ThreatStatistics;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/api/security")
public class SignalSciencesController {
@Autowired
private SignalSciencesClient client;
@Autowired
private ThreatMonitor threatMonitor;
@GetMapping("/threats/recent")
public ResponseEntity<List<Threat>> getRecentThreats(@RequestParam(defaultValue = "50") int limit) {
try {
List<Threat> threats = client.getRecentThreats("default", limit);
return ResponseEntity.ok(threats);
} catch (SignalSciencesException e) {
return ResponseEntity.internalServerError().build();
}
}
@GetMapping("/analytics/requests")
public ResponseEntity<RequestAnalytics> getRequestAnalytics(
@RequestParam Long from,
@RequestParam Long until,
@RequestParam(required = false) String interval) {
try {
AnalyticsQuery query = new AnalyticsQuery(new Date(from), new Date(until));
if (interval != null) {
query.setInterval(interval);
}
RequestAnalytics analytics = client.getRequestAnalytics("default", query);
return ResponseEntity.ok(analytics);
} catch (SignalSciencesException e) {
return ResponseEntity.internalServerError().build();
}
}
@GetMapping("/monitoring/stats")
public ResponseEntity<ThreatStatistics> getMonitoringStats() {
ThreatStatistics stats = threatMonitor.getStatistics();
return ResponseEntity.ok(stats);
}
@GetMapping("/alerts")
public ResponseEntity<List<Alert>> getAlerts(
@RequestParam(required = false) Long since,
@RequestParam(required = false) Long until,
@RequestParam(defaultValue = "50") int limit) {
try {
AlertQuery query = new AlertQuery();
if (since != null) query.setSince(new Date(since));
if (until != null) query.setUntil(new Date(until));
query.setLimit(limit);
List<Alert> alerts = client.getAlerts("default", query);
return ResponseEntity.ok(alerts);
} catch (SignalSciencesException e) {
return ResponseEntity.internalServerError().build();
}
}
@PostMapping("/rules")
public ResponseEntity<CustomRule> createCustomRule(@RequestBody CustomRule rule) {
try {
CustomRule created = client.createCustomRule("default", rule);
return ResponseEntity.ok(created);
} catch (SignalSciencesException e) {
return ResponseEntity.internalServerError().build();
}
}
@GetMapping("/health")
public ResponseEntity<Map<String, Object>> health() {
try {
List<Site> sites = client.getSites();
boolean healthy = !sites.isEmpty();
return ResponseEntity.ok(Map.of(
"status", healthy ? "healthy" : "degraded",
"sitesCount", sites.size(),
"timestamp", System.currentTimeMillis()
));
} catch (SignalSciencesException e) {
return ResponseEntity.ok(Map.of(
"status", "unhealthy",
"error", e.getMessage(),
"timestamp", System.currentTimeMillis()
));
}
}
}
5. Web Application Firewall Filter
// WAFRequestFilter.java
package com.signalsciences.filter;
import com.signalsciences.SignalSciencesClient;
import com.signalsciences.Threat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
@Component
public class WAFRequestFilter implements Filter {
private static final Logger logger = LoggerFactory.getLogger(WAFRequestFilter.class);
@Autowired
private SignalSciencesClient client;
private final Set<String> suspiciousUserAgents = Set.of(
"sqlmap", "nikto", "metasploit", "nmap", "burpsuite", "w3af"
);
private final Set<String> blockedIPs = Collections.synchronizedSet(new HashSet<>());
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String clientIP = getClientIP(httpRequest);
String userAgent = httpRequest.getHeader("User-Agent");
String path = httpRequest.getRequestURI();
String method = httpRequest.getMethod();
// Check if IP is blocked
if (blockedIPs.contains(clientIP)) {
logger.warn("Blocked request from blacklisted IP: {}", clientIP);
httpResponse.setStatus(403);
httpResponse.getWriter().write("Access denied");
return;
}
// Analyze request for threats
ThreatAnalysis analysis = analyzeRequest(httpRequest);
if (analysis.isSuspicious()) {
logger.warn("Suspicious request detected from {}: {}", clientIP, analysis.getReason());
// Log threat for monitoring
logThreat(clientIP, userAgent, path, method, analysis);
// Block critical threats
if (analysis.isCritical()) {
blockedIPs.add(clientIP);
httpResponse.setStatus(403);
httpResponse.getWriter().write("Request blocked by WAF");
return;
}
}
chain.doFilter(request, response);
}
private String getClientIP(HttpServletRequest request) {
String xForwardedFor = request.getHeader("X-Forwarded-For");
if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
return xForwardedFor.split(",")[0].trim();
}
return request.getRemoteAddr();
}
private ThreatAnalysis analyzeRequest(HttpServletRequest request) {
ThreatAnalysis analysis = new ThreatAnalysis();
String clientIP = getClientIP(request);
String userAgent = request.getHeader("User-Agent");
String path = request.getRequestURI();
String queryString = request.getQueryString();
// Check for suspicious user agents
if (userAgent != null) {
String lowerUserAgent = userAgent.toLowerCase();
for (String suspicious : suspiciousUserAgents) {
if (lowerUserAgent.contains(suspicious)) {
analysis.addSuspicion("Suspicious User-Agent: " + userAgent);
analysis.setCritical(true);
}
}
}
// Check for SQL injection patterns
if (containsSQLInjection(path) || (queryString != null && containsSQLInjection(queryString))) {
analysis.addSuspicion("SQL injection attempt detected");
analysis.setCritical(true);
}
// Check for path traversal
if (containsPathTraversal(path)) {
analysis.addSuspicion("Path traversal attempt detected");
analysis.setCritical(true);
}
// Check for XSS attempts
if (containsXSS(path) || (queryString != null && containsXSS(queryString))) {
analysis.addSuspicion("XSS attempt detected");
analysis.setCritical(true);
}
// Rate limiting (simplified)
if (isRateLimited(clientIP)) {
analysis.addSuspicion("Rate limit exceeded");
analysis.setCritical(true);
}
return analysis;
}
private boolean containsSQLInjection(String input) {
if (input == null) return false;
String[] sqlPatterns = {
"union.*select", "select.*from", "insert.*into", "update.*set",
"delete.*from", "drop.*table", "1=1", "or.*1=1", "';", "--"
};
String lowerInput = input.toLowerCase();
return Arrays.stream(sqlPatterns)
.anyMatch(pattern -> lowerInput.matches(".*" + pattern + ".*"));
}
private boolean containsPathTraversal(String input) {
if (input == null) return false;
return input.contains("../") || input.contains("..\\") || input.contains("/etc/passwd");
}
private boolean containsXSS(String input) {
if (input == null) return false;
String[] xssPatterns = {
"<script>", "javascript:", "onload=", "onerror=", "onclick=",
"alert\\(", "document\\.cookie", "<iframe>"
};
String lowerInput = input.toLowerCase();
return Arrays.stream(xssPatterns)
.anyMatch(pattern -> lowerInput.contains(pattern));
}
private boolean isRateLimited(String clientIP) {
// Simplified rate limiting - in production, use Redis or similar
// This is just a basic example
return false;
}
private void logThreat(String clientIP, String userAgent, String path,
String method, ThreatAnalysis analysis) {
// In production, this would send data to Signal Sciences
logger.warn("THREAT: IP={}, Method={}, Path={}, UserAgent={}, Reason={}",
clientIP, method, path, userAgent, analysis.getReason());
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
logger.info("WAF Request Filter initialized");
}
@Override
public void destroy() {
logger.info("WAF Request Filter destroyed");
}
}
// ThreatAnalysis.java
package com.signalsciences.filter;
import java.util.ArrayList;
import java.util.List;
public class ThreatAnalysis {
private List<String> suspicions;
private boolean critical;
public ThreatAnalysis() {
this.suspicions = new ArrayList<>();
this.critical = false;
}
public void addSuspicion(String suspicion) {
suspicions.add(suspicion);
}
public boolean isSuspicious() {
return !suspicions.isEmpty();
}
public boolean isCritical() {
return critical;
}
public void setCritical(boolean critical) {
this.critical = critical;
}
public String getReason() {
return String.join("; ", suspicions);
}
public List<String> getSuspicions() {
return new ArrayList<>(suspicions);
}
}
6. Security Dashboard Service
// SecurityDashboardService.java
package com.signalsciences.dashboard;
import com.signalsciences.*;
import com.signalsciences.monitoring.ThreatMonitor;
import com.signalsciences.monitoring.ThreatStatistics;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@Service
public class SecurityDashboardService {
@Autowired
private SignalSciencesClient client;
@Autowired
private ThreatMonitor threatMonitor;
private final Map<String, DashboardMetrics> metricsCache = new ConcurrentHashMap<>();
private final int CACHE_TTL_MINUTES = 5;
public SecurityDashboard getDashboard() throws SignalSciencesException {
SecurityDashboard dashboard = new SecurityDashboard();
dashboard.setGeneratedAt(new Date());
// Get real-time threats
ThreatStatistics threatStats = threatMonitor.getStatistics();
dashboard.setThreatStatistics(threatStats);
// Get request analytics for last 24 hours
Date now = new Date();
Date yesterday = new Date(now.getTime() - (24 * 60 * 60 * 1000));
AnalyticsQuery query = new AnalyticsQuery(yesterday, now);
RequestAnalytics requestAnalytics = client.getRequestAnalytics("default", query);
dashboard.setRequestAnalytics(requestAnalytics);
// Get recent alerts
AlertQuery alertQuery = new AlertQuery();
alertQuery.setSince(yesterday);
alertQuery.setLimit(20);
List<Alert> alerts = client.getAlerts("default", alertQuery);
dashboard.setRecentAlerts(alerts);
// Get top threats
List<Threat> topThreats = threatMonitor.getRecentThreats(10);
dashboard.setTopThreats(topThreats);
// Calculate security score
double securityScore = calculateSecurityScore(threatStats, requestAnalytics);
dashboard.setSecurityScore(securityScore);
dashboard.setSecurityLevel(getSecurityLevel(securityScore));
return dashboard;
}
public ThreatReport generateThreatReport(Date from, Date until) throws SignalSciencesException {
ThreatReport report = new ThreatReport();
report.setFrom(from);
report.setUntil(until);
// Get threats in time range
AnalyticsQuery query = new AnalyticsQuery(from, until);
RequestAnalytics analytics = client.getRequestAnalytics("default", query);
// Analyze threat patterns
Map<String, ThreatPattern> patterns = analyzeThreatPatterns(analytics);
report.setThreatPatterns(patterns);
// Generate recommendations
List<SecurityRecommendation> recommendations = generateRecommendations(analytics, patterns);
report.setRecommendations(recommendations);
// Calculate metrics
ThreatMetrics metrics = calculateThreatMetrics(analytics);
report.setMetrics(metrics);
return report;
}
@Scheduled(fixedRate = 300000) // Update every 5 minutes
public void updateMetricsCache() {
try {
SecurityDashboard dashboard = getDashboard();
DashboardMetrics metrics = new DashboardMetrics(dashboard);
metricsCache.put("current", metrics);
} catch (SignalSciencesException e) {
System.err.println("Failed to update metrics cache: " + e.getMessage());
}
}
private double calculateSecurityScore(ThreatStatistics threatStats, RequestAnalytics analytics) {
double score = 100.0;
// Deduct for critical threats
score -= threatStats.getCriticalThreats() * 5;
// Deduct for high blocked request rate
if (analytics.getTotalRequests() > 0) {
double blockRate = (double) analytics.getBlockedRequests() / analytics.getTotalRequests();
if (blockRate > 0.1) { // More than 10% blocked
score -= 20;
}
}
// Deduct for high attack rate
if (analytics.getTotalRequests() > 0) {
double attackRate = analytics.getAttackTypes().values().stream()
.mapToInt(Integer::intValue).sum() / (double) analytics.getTotalRequests();
if (attackRate > 0.05) { // More than 5% attacks
score -= 15;
}
}
return Math.max(score, 0);
}
private String getSecurityLevel(double score) {
if (score >= 90) return "EXCELLENT";
if (score >= 80) return "GOOD";
if (score >= 70) return "FAIR";
if (score >= 60) return "POOR";
return "CRITICAL";
}
private Map<String, ThreatPattern> analyzeThreatPatterns(RequestAnalytics analytics) {
Map<String, ThreatPattern> patterns = new HashMap<>();
// Analyze by attack type
analytics.getAttackTypes().forEach((type, count) -> {
ThreatPattern pattern = new ThreatPattern();
pattern.setType("ATTACK_TYPE");
pattern.setValue(type);
pattern.setCount(count);
pattern.setSeverity(calculateAttackSeverity(type, count));
patterns.put("ATTACK_" + type, pattern);
});
// Analyze by IP
analytics.getTopIPs().forEach((ip, count) -> {
if (count > 10) { // Only consider IPs with significant activity
ThreatPattern pattern = new ThreatPattern();
pattern.setType("SUSPICIOUS_IP");
pattern.setValue(ip);
pattern.setCount(count);
pattern.setSeverity(count > 50 ? "HIGH" : "MEDIUM");
patterns.put("IP_" + ip, pattern);
}
});
return patterns;
}
private String calculateAttackSeverity(String attackType, int count) {
if (count > 100) return "CRITICAL";
if (count > 50) return "HIGH";
if (count > 20) return "MEDIUM";
return "LOW";
}
private List<SecurityRecommendation> generateRecommendations(
RequestAnalytics analytics, Map<String, ThreatPattern> patterns) {
List<SecurityRecommendation> recommendations = new ArrayList<>();
// Check for SQL injection patterns
if (patterns.containsKey("ATTACK_sql_injection")) {
recommendations.add(new SecurityRecommendation(
"SQL_INJECTION_PROTECTION",
"Implement additional SQL injection protection rules",
"HIGH",
"Add custom rules to block common SQL injection patterns"
));
}
// Check for XSS patterns
if (patterns.containsKey("ATTACK_xss")) {
recommendations.add(new SecurityRecommendation(
"XSS_PROTECTION",
"Enhance XSS protection",
"HIGH",
"Update WAF rules to detect advanced XSS attempts"
));
}
// Check for high block rate
if (analytics.getTotalRequests() > 0) {
double blockRate = (double) analytics.getBlockedRequests() / analytics.getTotalRequests();
if (blockRate > 0.15) {
recommendations.add(new SecurityRecommendation(
"FALSE_POSITIVES",
"Review false positives",
"MEDIUM",
"High block rate may indicate false positives. Review blocked requests."
));
}
}
return recommendations;
}
private ThreatMetrics calculateThreatMetrics(RequestAnalytics analytics) {
ThreatMetrics metrics = new ThreatMetrics();
metrics.setTotalRequests(analytics.getTotalRequests());
metrics.setBlockedRequests(analytics.getBlockedRequests());
metrics.setAttackRequests(analytics.getAttackTypes().values().stream()
.mapToInt(Integer::intValue).sum());
// Calculate rates
if (analytics.getTotalRequests() > 0) {
metrics.setBlockRate((double) analytics.getBlockedRequests() / analytics.getTotalRequests());
metrics.setAttackRate((double) metrics.getAttackRequests() / analytics.getTotalRequests());
}
return metrics;
}
}
// Dashboard Models
package com.signalsciences.dashboard;
import com.signalsciences.*;
import com.signalsciences.monitoring.ThreatStatistics;
import java.util.*;
public class SecurityDashboard {
private Date generatedAt;
private double securityScore;
private String securityLevel;
private ThreatStatistics threatStatistics;
private RequestAnalytics requestAnalytics;
private List<Alert> recentAlerts;
private List<Threat> topThreats;
// Constructors, getters, and setters
public SecurityDashboard() {}
public Date getGeneratedAt() { return generatedAt; }
public void setGeneratedAt(Date generatedAt) { this.generatedAt = generatedAt; }
public double getSecurityScore() { return securityScore; }
public void setSecurityScore(double securityScore) { this.securityScore = securityScore; }
public String getSecurityLevel() { return securityLevel; }
public void setSecurityLevel(String securityLevel) { this.securityLevel = securityLevel; }
public ThreatStatistics getThreatStatistics() { return threatStatistics; }
public void setThreatStatistics(ThreatStatistics threatStatistics) { this.threatStatistics = threatStatistics; }
public RequestAnalytics getRequestAnalytics() { return requestAnalytics; }
public void setRequestAnalytics(RequestAnalytics requestAnalytics) { this.requestAnalytics = requestAnalytics; }
public List<Alert> getRecentAlerts() { return recentAlerts; }
public void setRecentAlerts(List<Alert> recentAlerts) { this.recentAlerts = recentAlerts; }
public List<Threat> getTopThreats() { return topThreats; }
public void setTopThreats(List<Threat> topThreats) { this.topThreats = topThreats; }
}
public class ThreatReport {
private Date from;
private Date until;
private Map<String, ThreatPattern> threatPatterns;
private List<SecurityRecommendation> recommendations;
private ThreatMetrics metrics;
// Constructors, getters, and setters
public ThreatReport() {}
public Date getFrom() { return from; }
public void setFrom(Date from) { this.from = from; }
public Date getUntil() { return until; }
public void setUntil(Date until) { this.until = until; }
public Map<String, ThreatPattern> getThreatPatterns() { return threatPatterns; }
public void setThreatPatterns(Map<String, ThreatPattern> threatPatterns) { this.threatPatterns = threatPatterns; }
public List<SecurityRecommendation> getRecommendations() { return recommendations; }
public void setRecommendations(List<SecurityRecommendation> recommendations) { this.recommendations = recommendations; }
public ThreatMetrics getMetrics() { return metrics; }
public void setMetrics(ThreatMetrics metrics) { this.metrics = metrics; }
}
public class ThreatPattern {
private String type;
private String value;
private int count;
private String severity;
// Constructors, getters, and setters
public ThreatPattern() {}
public String getType() { return type; }
public void setType(String type) { this.type = type; }
public String getValue() { return value; }
public void setValue(String value) { this.value = value; }
public int getCount() { return count; }
public void setCount(int count) { this.count = count; }
public String getSeverity() { return severity; }
public void setSeverity(String severity) { this.severity = severity; }
}
public class SecurityRecommendation {
private String id;
private String title;
private String severity;
private String description;
private String action;
public SecurityRecommendation(String id, String title, String severity, String description) {
this.id = id;
this.title = title;
this.severity = severity;
this.description = description;
}
// Getters and setters
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
public String getSeverity() { return severity; }
public void setSeverity(String severity) { this.severity = severity; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public String getAction() { return action; }
public void setAction(String action) { this.action = action; }
}
public class ThreatMetrics {
private int totalRequests;
private int blockedRequests;
private int attackRequests;
private double blockRate;
private double attackRate;
// Constructors, getters, and setters
public ThreatMetrics() {}
public int getTotalRequests() { return totalRequests; }
public void setTotalRequests(int totalRequests) { this.totalRequests = totalRequests; }
public int getBlockedRequests() { return blockedRequests; }
public void setBlockedRequests(int blockedRequests) { this.blockedRequests = blockedRequests; }
public int getAttackRequests() { return attackRequests; }
public void setAttackRequests(int attackRequests) { this.attackRequests = attackRequests; }
public double getBlockRate() { return blockRate; }
public void setBlockRate(double blockRate) { this.blockRate = blockRate; }
public double getAttackRate() { return attackRate; }
public void setAttackRate(double attackRate) { this.attackRate = attackRate; }
}
public class DashboardMetrics {
private SecurityDashboard dashboard;
private Date cachedAt;
public DashboardMetrics(SecurityDashboard dashboard) {
this.dashboard = dashboard;
this.cachedAt = new Date();
}
// Getters and setters
public SecurityDashboard getDashboard() { return dashboard; }
public void setDashboard(SecurityDashboard dashboard) { this.dashboard = dashboard; }
public Date getCachedAt() { return cachedAt; }
public void setCachedAt(Date cachedAt) { this.cachedAt = cachedAt; }
}
7. Application Configuration
# application.yml
spring:
application:
name: signal-sciences-integration
signalsciences:
baseUrl: https://dashboard.signalsciences.net
email: ${SIGSCI_EMAIL:}
apiToken: ${SIGSCI_API_TOKEN:}
corpName: ${SIGSCI_CORP_NAME:}
siteName: ${SIGSCI_SITE_NAME:default}
monitoring:
enabled: true
interval: 60
server:
port: 8080
management:
endpoints:
web:
exposure:
include: health,metrics,info
endpoint:
health:
show-details: always
logging:
level:
com.signalsciences: DEBUG
Key Features:
- Complete API Integration: Full Signal Sciences REST API client
- Real-time Threat Monitoring: Continuous monitoring with event listeners
- Spring Boot Integration: Seamless framework integration
- WAF Request Filter: In-application security filtering
- Security Dashboard: Comprehensive security analytics and reporting
- Custom Rules Management: Dynamic rule creation and management
- IP List Management: Whitelist/blacklist functionality
- Alert System: Real-time security alerts and notifications
This implementation provides enterprise-grade Signal Sciences WAF integration for Java applications, enabling comprehensive web application security monitoring, threat detection, and real-time protection.