pawarprasad123 commented on code in PR #742:
URL: https://github.com/apache/atlas/pull/742#discussion_r3862315159


##########
server-common/src/main/java/org/apache/atlas/server/common/filters/AtlasHeaderFilter.java:
##########
@@ -34,7 +34,10 @@ public void init(FilterConfig filterConfig) {
 
     @Override
     public void doFilter(ServletRequest request, ServletResponse response, 
FilterChain filterChain) throws IOException, ServletException {
-        setHeaders((HttpServletResponse) response);
+        String cspNonce = HeadersUtil.generateCspNonce();

Review Comment:
   (String cspNonce = HeadersUtil.generateCspNonce();)
   AtlasHeaderFilter generates its own nonce and overwrites the request 
attribute set by Spring Security's header writer. For admin endpoints that pass 
through both filters, the nonce in the CSP header may not match 
atlas.csp.nonce. Should read existing nonce from request attribute first, not 
regenerate.
   
   



##########
server-common/src/main/java/org/apache/atlas/server/common/security/AtlasSecurityConfig.java:
##########
@@ -129,7 +129,15 @@ protected void configureCommonHttpSecurity(HttpSecurity 
httpSecurity) throws Exc
                 .authorizeRequests().anyRequest().authenticated()
                 .and()
                 .headers()
-                .addHeaderWriter(new 
StaticHeadersWriter(HeadersUtil.CONTENT_SEC_POLICY_KEY, 
HeadersUtil.getHeaderMap(HeadersUtil.CONTENT_SEC_POLICY_KEY)))
+                .addHeaderWriter((request, response) -> {

Review Comment:
   String cspNonce = HeadersUtil.generateCspNonce();)
   
   -This generates a new nonce independently of other filters. If any 
downstream filter calls setSecurityHeaders(wrapper) without passing this same 
nonce, the header and request attribute will diverge. Use a shared 
getOrCreateNonce(request) helper and ensure all header-writing paths consume 
the same value.
   
   



##########
webapp/src/test/java/org/apache/atlas/web/filters/HeaderUtilsTest.java:
##########
@@ -98,6 +100,18 @@ public void testDefaultHeadersArePresent() {
         assertEquals("1; mode=block", 
HeadersUtil.getHeaderMap(HeadersUtil.X_XSS_PROTECTION_KEY));
     }
 
+    @Test
+    public void testContentSecurityPolicyValueUsesNonce() {

Review Comment:
   (testContentSecurityPolicyValueUsesNonce)
   
   Good start. Please also add tests in server-common/.../HeadersUtilTest.java 
for: (1) custom CSP override with and without ${nonce}, (2) generateCspNonce() 
produces unique nonces, (3) both script-src and style-src placeholders are 
replaced, (4) null/empty nonce fallback behavior.
   
   



##########
server-common/src/main/java/org/apache/atlas/server/common/filters/AtlasHeaderFilter.java:
##########
@@ -43,8 +46,12 @@ public void destroy() {
     }
 
     public void setHeaders(HttpServletResponse httpResponse) {

Review Comment:
   (public void setHeaders(HttpServletResponse httpResponse))
   This overload calls `generateCspNonce()` again, producing yet another nonce 
if invoked directly. Consider removing this pattern or delegating to the 
request-scoped nonce to avoid accidental mismatch in tests or future callers.



##########
server-common/src/main/java/org/apache/atlas/server/common/filters/HeadersUtil.java:
##########
@@ -71,8 +77,40 @@ public static void 
setHeaderMapAttributes(AtlasResponseRequestWrapper responseWr
         responseWrapper.setHeader(headerKey, HEADER_MAP.get(headerKey));
     }
 
+    public static String generateCspNonce() {
+        byte[] nonceBytes = new byte[CSP_NONCE_BYTES];
+
+        CSP_NONCE_RANDOM.nextBytes(nonceBytes);
+
+        return Base64.getEncoder().withoutPadding().encodeToString(nonceBytes);
+    }
+
+    public static String getContentSecurityPolicyValue(String cspNonce) {
+        String cspTemplate = HEADER_MAP.get(CONTENT_SEC_POLICY_KEY);
+
+        if (cspTemplate == null) {
+            return null;
+        }
+
+        if (cspNonce == null || cspNonce.trim().isEmpty()) {
+            cspNonce = generateCspNonce();
+        }
+
+        return cspTemplate.replace(CONTENT_SEC_POLICY_NONCE_PLACEHOLDER, 
cspNonce);
+    }
+
+    public static void setSecurityHeaders(AtlasResponseRequestWrapper 
responseWrapper, String cspNonce) {
+        HEADER_MAP.forEach((key, value) -> {
+            if (CONTENT_SEC_POLICY_KEY.equals(key)) {
+                responseWrapper.setHeader(key, 
getContentSecurityPolicyValue(cspNonce));
+            } else {
+                responseWrapper.setHeader(key, value);
+            }
+        });
+    }
+

Review Comment:
    setSecurityHeaders(AtlasResponseRequestWrapper responseWrapper)
   -
   setSecurityHeaders(wrapper) generates a fresh nonce on every call. This is 
invoked from AtlasAuthenticationFilter, AtlasCSRFPreventionFilter, 
AtlasHeaderPreAuthFilter, AtlasKnoxSSOAuthenticationFilter, and 
AtlasHttpServlet, each potentially overwriting the CSP header set by 
AtlasSecurityConfig with a different nonce. Please add 
getOrCreateNonce(HttpServletRequest request) that generates once per request 
(stored in CONTENT_SEC_POLICY_NONCE_REQUEST_ATTRIBUTE) and reuse it in all call 
sites.



##########
server-common/src/main/java/org/apache/atlas/server/common/filters/HeadersUtil.java:
##########
@@ -40,11 +42,13 @@ public class HeadersUtil {
     public static final String X_XSS_PROTECTION_KEY                = 
"X-XSS-Protection";
     public static final String STRICT_TRANSPORT_SEC_KEY            = 
"Strict-Transport-Security";
     public static final String CONTENT_SEC_POLICY_KEY              = 
"Content-Security-Policy";
+    public static final String CONTENT_SEC_POLICY_NONCE_PLACEHOLDER = 
"${nonce}";
+    public static final String CONTENT_SEC_POLICY_NONCE_REQUEST_ATTRIBUTE = 
"atlas.csp.nonce";
     public static final String X_FRAME_OPTIONS_VAL                 = "DENY";
     public static final String X_CONTENT_TYPE_OPTIONS_VAL          = "nosniff";
     public static final String X_XSS_PROTECTION_VAL                = "1; 
mode=block";
     public static final String STRICT_TRANSPORT_SEC_VAL            = 
"max-age=31536000; includeSubDomains";
-    public static final String CONTENT_SEC_POLICY_VAL              = 
"default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob: 
data:; connect-src 'self'; img-src 'self' blob: data:; style-src 'self' 
'unsafe-inline';font-src 'self' data:";
+    public static final String CONTENT_SEC_POLICY_VAL              = 
"default-src 'self'; script-src 'self' 'nonce-${nonce}' blob:; connect-src 
'self'; img-src 'self' blob: data:; style-src 'self' 'nonce-${nonce}'; font-src 
'self' data:; object-src 'none'; base-uri 'self'; frame-ancestors 'none';";

Review Comment:
   (CONTENT_SEC_POLICY_VAL)
   
   Policy change looks good — removes unsafe directives and adds nonce 
placeholders for both `script-src` and `style-src`.
   
   Note: this policy alone will block runtime `<style>` tags (e.g. MUI/Emotion 
in React Dashboard) unless:
   1. HTML responses inject matching `nonce="..."` on script/style tags, and
   2. The React UI reads the nonce and passes it to Emotion cache.
   
   The HTML injection pipeline is not part of this PR — please confirm the 
follow-up plan.



##########
server-common/src/main/java/org/apache/atlas/server/common/filters/AtlasHeaderFilter.java:
##########
@@ -34,7 +34,10 @@ public void init(FilterConfig filterConfig) {
 
     @Override
     public void doFilter(ServletRequest request, ServletResponse response, 
FilterChain filterChain) throws IOException, ServletException {
-        setHeaders((HttpServletResponse) response);
+        String cspNonce = HeadersUtil.generateCspNonce();

Review Comment:
   This is general:
   Missing filter updates (general comment)
   The following files still call 
HeadersUtil.setSecurityHeaders(responseWrapper) without a request-scoped nonce 
and are not updated in this PR:
   
   - AtlasAuthenticationFilter.java:397
   - AtlasCSRFPreventionFilter.java:107
   - AtlasHeaderPreAuthFilter.java:111
   - AtlasKnoxSSOAuthenticationFilter.java:126
   - AtlasHttpServlet.java:39
   These need to pass the same per-request nonce to avoid header/attribute 
mismatch.



##########
server-common/src/main/java/org/apache/atlas/server/common/filters/HeadersUtil.java:
##########
@@ -71,8 +77,40 @@ public static void 
setHeaderMapAttributes(AtlasResponseRequestWrapper responseWr
         responseWrapper.setHeader(headerKey, HEADER_MAP.get(headerKey));
     }
 
+    public static String generateCspNonce() {
+        byte[] nonceBytes = new byte[CSP_NONCE_BYTES];
+
+        CSP_NONCE_RANDOM.nextBytes(nonceBytes);
+
+        return Base64.getEncoder().withoutPadding().encodeToString(nonceBytes);
+    }
+
+    public static String getContentSecurityPolicyValue(String cspNonce) {

Review Comment:
   (getContentSecurityPolicyValue(String cspNonce))
   -
   When atlas.headers.Content-Security-Policy is overridden via config without 
the ${nonce} placeholder, this method silently returns a policy with no nonce. 
Consider logging a warning when the template doesn't contain 
CONTENT_SEC_POLICY_NONCE_PLACEHOLDER, or rejecting unsafe custom overrides.
   
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to