Java Storage and Operations

Source and package versions

One AIWAF repository. Python: py/aiwaf/ · Node.js: js/ · Rust/WASM: rust/ · Java: java/. Source and canonical README. Versions shown describe the source checkout; package releases are independent. Current Python/Node source targets are aiwaf 1.1.8 (Python) and aiwaf 1.1.5 (npm), with Rust/Python 0.2.7 and WASM 0.2.5 and Java 1.3.5. Sandbox guides retain their separately pinned builds.

Version and source build

Java 1.3.0 adds hardened Redis operation to the scoped distributed state introduced in 1.2.0. The version in java/pom.xml describes the source checkout; verify Maven Central availability before adding that version to an application.

git clone https://github.com/aiwaf-project/aiwaf.git
cd aiwaf/java
mvn test
mvn -Dgpg.skip=true package

Configuration, Redis, and operational commands

AreaMain AiwafConfig fields
Rate limitingrateLimitEnabled, rateLimitScope, rateLimitWindowSeconds, rateLimitMax, rateLimitFloodThreshold
HeadersheaderValidationEnabled, requiredHeadersByMethod, minHeaderQualityScore, size/count limits
Requestbody, parameter, method, and content-type limits
ProxiestrustedProxyCidrs, maxForwardedForEntries
ExemptionsexemptIps, exemptPaths, autoExemptPathPrefixes
GeoIPgeoBlockEnabled, geoAllowedCountries, geoBlockedCountries, geoIpDatabasePath, cache limits
Route manifestpathManifestEnabled, pathManifestPath, pathRules
UUID checksuuidTamperEnabled, uuidScoreWindowSeconds, uuidScoreBlockThreshold, signal weights, uuidParameterNames
AIaiEnabled, aiModelPath, aiAnomalyScoreThreshold
StoragestorageBackend, storageFilePath, storageRedisUrl, storageKeyPrefix, storageRedisFailureMode, Redis timeout and pool limits
TelemetryobservabilityEnabled

GeoIP uses the bundled MMDB through the native Java reader; it does not require the external mmdblookup executable. A valid X-Country value is accepted only from a peer in trustedProxyCidrs; otherwise AIWAF resolves the client address itself. Default blocklist calls use Python-compatible reputation scoring and temporary escalation (15 minutes, 1 hour, then 24 hours). Use BlocklistManager.blockPermanent(ip, reason) for an explicit permanent administrative block.

storageBackend="redis" makes rate-limit buckets, honeypot timing, weighted UUID scores, recent-request anomaly state, blocklist data, exemptions, geo policy, and learned keywords visible to every application instance using the same key prefix. Redis enforcement updates use atomic server-side scripts. Memory, file, CSV, and SQLite engines keep request state isolated per AiwafEngine; constructing another engine no longer replaces an existing engine's stores. The static RuntimeStorage and BlocklistManager methods remain compatibility facades for command-line and administrative code.

The Java 1.3 Redis backend supports standalone Redis only. Sentinel and Cluster configurations are rejected during validation instead of silently operating with incomplete semantics. fail_closed is the default: an unavailable Redis instance prevents startup or raises a request-path storage failure, which results in the application denying availability rather than bypassing protection. fail_open permits startup and returns non-blocking enforcement fallbacks while Redis is unavailable; failed mutations return false at the StorageBackend boundary. Connection, socket, pool size, and pool wait limits are bounded and configurable. RedisStorage.diagnostics() reports operation/failure counts, latency, and live pool utilization.

Redis keys include a state-schema version, and each base key prefix has an atomic compatibility marker. Releases using the same schema can share state during a rolling upgrade. A runtime with an incompatible schema refuses the namespace—even in fail_open mode. Use a unique key prefix per application and environment; deploy an incompatible schema with a new prefix, migrate deliberately, then retire the old namespace. Serialized persistent values remain JSON within a schema version.

New Java models use the Python-aligned six-feature schema and are written as safe JSON containing the Python aiwaf_rust.IsolationForest state. Python can restore Java-generated forest state, and Java can load Python Rust-model artifacts. Existing signed Java binary artifacts, including nine-feature models, remain readable through the restricted legacy loader. Scikit-learn object artifacts are intentionally unsupported.

Java operational commands mirror the common Python workflow:

aiwaf-cli status
aiwaf-cli diagnose --model model.json
aiwaf-cli blocked
aiwaf-cli unblock 203.0.113.10
aiwaf-cli clear
aiwaf-cli train --events events.json --out model.json --backend java
aiwaf-cli replay --cases replay.json
aiwaf-cli model status --path model.json
aiwaf-cli logs --dir aiwaf_logs

Build Java from the repository root:

cd java
mvn test
mvn -Dgpg.skip=true package

The build produces the main, source, and Javadoc JARs under java/target/. The main JAR embeds the root license as META-INF/LICENSE. FastR training is optional and falls back to the Java trainer when R or jsonlite is unavailable.

Spring property examples

Spring Boot applications are protected automatically. Adding aiwaf-java creates AiwafConfig, AiwafEngine, and the ordered AiwafFilter; discovers live MVC routes, route annotations, and JPA UUID fields; and applies request controls before the controller plus post-response scoring with the real status and timing. Set aiwaf.enabled=false to disable auto-configuration.

aiwaf.rate-limit.max=60
aiwaf.rate-limit.window-seconds=60
aiwaf.geo.enabled=true
aiwaf.geo.blocked-countries=CN,RU
aiwaf.path-manifest.path=.aiwaf/paths.json
# Use one namespace and shared enforcement state across application instances.
aiwaf.storage.backend=redis
aiwaf.storage.redis-url=redis://localhost:6379/0
aiwaf.storage.key-prefix=my-service
# Redis is fail-closed by default. Every wait is bounded.
aiwaf.storage.redis-failure-mode=fail_closed
aiwaf.storage.redis-connection-timeout-millis=1000
aiwaf.storage.redis-socket-timeout-millis=2000
aiwaf.storage.redis-pool-max-total=32
aiwaf.storage.redis-pool-max-idle=16
aiwaf.storage.redis-pool-min-idle=0
aiwaf.storage.redis-pool-max-wait-millis=250

Set aiwaf.config-file=/etc/aiwaf/config.json (or AIWAF_CONFIG_FILE) to load the same nested JSON configuration used by the Python runtime. Environment variables and Spring properties override file values. AiwafConfigFileCore also exposes load, save, deep-merge, and validation APIs for non-Spring applications.

Define an AiwafConfig, AiwafEngine, or AiwafFilter bean only when the application needs a custom replacement. For plain Spring MVC without Boot, register the filter directly; passing the application context enables the same live route discovery:

@Bean
AiwafFilter aiwafFilter(AiwafEngine engine, ApplicationContext context) {
    return new AiwafFilter(engine, context);
}

The live mapping integration honors @AiwafExempt, @AiwafExemptFrom, @AiwafOnly, and @AiwafRequireProtection without a controller list. Do not register AiwafInterceptor and AiwafFilter as independent enforcement layers for the same request.

Committed, streaming, and asynchronous responses are recorded but are not replaced after bytes have been sent.

UUID protection uses Python-compatible weighted signals: malformed input, valid UUID requests that resolve to 404, and successful requests that decay the score. UUID-valued query parameters and {uuid} route variables are supported. SpringUuidModelLookup optionally discovers UUID primary keys and unique UUID properties through the JPA metamodel; omit it when the application does not use JPA.

Generate a route manifest from the live Spring application rather than supplying controller methods manually:

java -cp "your-app.jar:aiwaf-java-1.3.5.jar" \
  com.aiwaf.cli.AiwafConsole init \
  --app com.example.Application \
  --output .aiwaf/paths.json

The command starts the application, reads every registered RequestMappingHandlerMapping, writes the shared schema_version/framework/context_hash/routes document, and then closes the temporary application context. At runtime, AiwafEngine loads this file automatically and appends its disabled middleware and rate-limit overrides after explicit pathRules, so explicit equal-prefix rules retain precedence. Set pathManifestEnabled=false or aiwaf.path-manifest.enabled=false to opt out.

Deployment

  • Configure the application to trust forwarding headers only from known proxy CIDRs.
  • Configure the outermost proxy to overwrite client-supplied forwarding headers.
  • Use Redis, a database, or another shared backend when multiple workers must share rate-limit, blocklist, or exemption state.
  • Keep health checks, static assets, and trusted webhook routes explicitly scoped instead of disabling protection globally.
  • Start anomaly detection in observe-only or conservative mode and tune it with representative normal traffic.
  • Rotate logs and exclude secrets, authorization headers, cookies, and personal data.
  • Sign model/configuration artifacts where the runtime supports HMAC verification.
  • Run AIWAF alongside normal secure-development controls and an edge/reverse-proxy layer.

Bounded SQL inspection

Java SQL inspection defaults to security.sql_injection_mode: "block"; monitor records findings without denying requests and off disables it. AIWAF_SQL_INJECTION_MODE is the environment override. Inspection honors the configured body-byte limit and returns HTTP 413 when inspection exceeds its budget. Previously learned benign keywords no longer block ordinary routes. Java remains a native Java implementation.

October 2026 release upgrade

The prepared source versions are Python 1.1.6, Rust/Python 0.2.5, Node.js 1.1.4, WASM 0.2.4, and Java 1.3.4. These are source targets; verify registry availability before installing. Python requires aiwaf-rust>=0.2.5, including the TrainingEvidence API. Node offline training requires the matching WASM receipt API.

  1. Back up policies, logs, models, and training evidence. Use the same absolute data and evidence directories for application workers and CLI trainers.
  2. Install the matching native companion before upgrading its host package: Rust before Python, WASM before Node. Preserve training_evidence.json and node_training_evidence.json across expiry, unblocking, restarts, and log rotation.
  3. Stop older file writers and restart all workers on the new code. Mixing old unlocked writers with new writers can still lose updates.
  4. In staging, train twice on identical logs, then verify handled evidence does not recreate a removed or expired block. Add genuinely fresh requests and confirm they must independently satisfy the enforcement threshold.
  5. Verify that listing and expiry checks preserve concurrently refreshed blocks and unrelated IPs. Check the raw expiry and backend location if entries disappear unexpectedly.

Java CSV and file storage

Java 1.3.4 reloads current storage under a shared JVM and OS sidecar lock for each operation. Reads filter expiry without rewriting disk; mutations preserve other instances' updates and report persistence failures. This adds file I/O. Java model training still does not add blocklist entries. Rate buckets and other per-engine memory state retain their existing isolation.

Lock recovery

Python training uses an OS file lock; Java CSV/file OS locks also release on process exit. Keep their stable sidecar lock files in place while workers run. Node uses lock directories for training and legacy CSV mutations; a crash can leave them behind. Confirm the owning process has stopped before removing a Node lock directory. Do not delete training receipts to clear a lock: doing so loses handled-evidence history.

Release checks

Local validation passed 247 Node tests across 67 suites with the coverage gate, 215 Java tests with 3 skips, and 38 Rust/WASM native tests. After the native dependency bump, 11 affected Python packaging tests passed through the appropriate Django and pytest runners. These checks do not replace full release CI, dependency audits, signing, or operating-system wheel builds. Build Linux/macOS Rust wheels using the release matrix; the local bundle contains a Windows x86-64 wheel.

For release maintainers: publish the WASM companion, refresh the Node lockfile from the registry to record its actual integrity, then run npm ci and the native integration checks. Do not substitute an older native dependency to satisfy a stale packaging test. See the changelog.