We recently had a security assessment that identified brute force vulnerabilities on our dispatcher URL. The assessment showed 190 consecutive login attempts were possible without any blocking mechanisms on /libs/granite/core/content/login.html.
As an immediate mitigation, I'm planning to add these Dispatcher deny rules to block direct access to authentication endpoints:
/0300 { /type "deny" /url "/system/sling/login" }/0301 { /type "deny" /url "/system/sling/logout" }/0302 { /type "deny" /url "/libs/granite/core/content/login*" }/0303 { /type "deny" /url "/login*" }/0304 { /type "deny" /url "*/j_security_check*" }/0305 { /type "deny" /url "/j_security_check*" }
The security report specifically mentioned the lack of protection on the j_security_check endpoint. Any guidance on comprehensive AEM brute force protection would be appreciated.
Solved! Go to Solution.
Views
Replies
Total Likes
Hi @georhe6
The recommended approach is to use whitelisting instead of blacklisting the URLs.
It's best practice to deny all by default and then explicitly allow only the necessary URLs.
Example
Hi @georhe6 ,
1. Looks like your Dispatcher rules are an effective first-level defense. They prevent unauthenticated users from reaching common login endpoints from the publish tier or the internet, which is crucial.
Here’s a slightly enhanced version of your rules for clarity:
/0300 { /type "deny" /url "/system/sling/login" }
/0301 { /type "deny" /url "/system/sling/logout" }
/0302 { /type "deny" /url "/libs/granite/core/content/login*" }
/0303 { /type "deny" /url "/login*" }
/0304 { /type "deny" /url "*j_security_check*" }
/0305 { /type "deny" /url "/j_security_check*" }
2. Only if:
You have custom login flows relying on that specific path on publish.
You accidentally apply these rules to author dispatchers, which would block legitimate logins for AEM users/admins.
To avoid issues:
Apply these rules only to Dispatcher in front of Publish.
If you're using SSO (SAML, OAuth, etc.), ensure these endpoints are still reachable internally or via specific allowed IPs.
3. AEM lacks robust built-in rate-limiting, but here are key strategies:
Use mod_ratelimit or mod_security in Apache HTTPD:
<Location "/libs/granite/core/content/login.html">
SetEnvIf Request_Method "POST" loginAttempt
<IfModule mod_ratelimit.c>
SetOutputFilter RATE_LIMIT
SetEnv rate-limit 1000
</IfModule>
</Location>
Or better, block repeated requests via mod_evasive or mod_security:
mod_evasive can detect rapid, repeated hits from same IP.
mod_security allows complex rules based on behavior.
Configure login token expiration and reuse policies via OSGi:
Apache Jackrabbit Oak TokenConfiguration
Adobe Granite Login Token Authentication Handler
Settings to review:
Token Expiration (tokenExpiration)
Max Token Count per user (tokenLimit)
Session invalidation on logout
Install or develop a custom authentication handler to:
Lock user after N failed login attempts.
Log and alert on brute force behavior.
4. Commonly used practices in AEM hardening guides:
Block all login endpoints on Publish Dispatcher.
Use WAFs like Akamai, AWS Shield, Cloudflare for rate-limiting and threat detection.
Use SSO/SAML/OAuth to offload authentication to secure providers.
Configure IP whitelisting for Author access.
Use mod_security rules to detect and block automated tools.
j_security_check is the form submission endpoint for classic AEM logins. It's the main target for brute-force POSTs.
You must:
Block j_security_check on publish dispatcher.
Monitor POST requests to it even on Author via logs or a WAF.
Hi @georhe6
The recommended approach is to use whitelisting instead of blacklisting the URLs.
It's best practice to deny all by default and then explicitly allow only the necessary URLs.
Example
@georhe6 Did you find the suggestions helpful? If you need more information, please let us know. If a response resolved your issue, kindly mark it as correct to help others in the future. Alternatively, if you discovered a solution on your own, we'd appreciate it if you could share it with the community. Thank you !
Views
Replies
Total Likes
Views
Likes
Replies
Views
Likes
Replies