Expand my Community achievements bar.

Join expert-led, customer-led sessions on Adobe Experience Manager Assets on August 20th at our Skill Exchange.

dispatcher, cloud-service, Content Security Policies, and configuration

Avatar

Level 1

 

we want to add the Content-Security-Policy header for our site ( Aem as Cloud) using dispatcher by adding the header in the site specific vhost file. 
we added as below 

Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://example.com; style-src 'self' 'unsafe-inline'; font-src 'self' data:;"

but header is not visible as part of the response headers. it is not working 

when we try using the cdn, through responseHeaderTransformer configuration. 

but i want add through dispatcher only ,  why it is not working via dispatcher ?

please guide me to resolve the issue and make it work with dispatcher configuration . 

 
<VirtualHost *:80>
ServerName "publish"
# Put names of which domains are used for your published site/content here
ServerAlias "*"
# Use a document root that matches the one in conf.dispatcher.d/default.farm
DocumentRoot "${DOCROOT}"
# URI dereferencing algorithm is applied at Sling's level, do not decode parameters here
AllowEncodedSlashes NoDecode
# Add header breadcrumbs for help in troubleshooting
SetEnvIfExpr "%{HTTP_HOST} == 'www.abc.com'" IS_WKKELOGG
<IfModule mod_headers.c>
Header add X-Vhost "publish"
 
Header always set X-Vhost "wk-Vhost"      ( this also not comming) 
 
# Apply CSP for WK Kellogg
# Header set Content-Security-Policy "default-src 'self'; script-src 'self' https://*.abc.com;" env=IS_WKKELOGG
 
# Apply CSP for Kashi
# Header set Content-Security-Policy "default-src 'self'; script-src 'self' https://*.kashi.com;" env=IS_KASHI
 
################## Start of CORS configuration ##################
 
        # Enable CORS handling in the dispatcher
        #
        # By default, CORS is handled by the AEM publish server.
        # By adding the section below, CORS will be handled in the dispatcher.
        # See the default.vhost file for a suggested dispatcher configuration. Note that:
        #   a. You will need to adapt the regex from default.vhost to match your CORS domains
        #   b. Remove the "Origin" header (if it exists) from the clientheaders.any file
        #   c. If you have any CORS domains configured in your AEM publish server origin, you have to move those to the dispatcher
        #       (i.e. accordingly update regex in default.vhost to match those domains)
        #
 
        SetEnvIfExpr "req_novary('Origin') == ''" CORSType=none CORSProcessing=false
        SetEnvIfExpr "req_novary('Origin') != ''" CORSType=cors CORSProcessing=true CORSTrusted=false
 
        SetEnvIfExpr "req_novary('Access-Control-Request-Method') == '' && %{REQUEST_METHOD} == 'OPTIONS' && req_novary('Origin') != ''" CORSType=invalidpreflight CORSProcessing=false
        SetEnvIfExpr "req_novary('Access-Control-Request-Method') != '' && %{REQUEST_METHOD} == 'OPTIONS' && req_novary('Origin') != ''" CORSType=preflight CORSProcessing=true CORSTrusted=false
        SetEnvIfExpr "req_novary('Origin') -strcmatch 'https://%{HTTP_HOST}*'" CORSType=samedomain CORSProcessing=false CORSTrusted=true
        SetEnvIfExpr "req_novary('Origin') -strcmatch 'http://%{HTTP_HOST}*'" CORSType=samedomain CORSProcessing=false CORSTrusted=true
 
        # For requests that require CORS processing, check if the Origin can be trusted
        SetEnvIfExpr "%{HTTP_HOST} =~ /(.*)/ " ParsedHost=$1
 
        ################## BEGIN EDITABLE SECTION: Adapt regex to match CORS origin(s) for applications
 
        ################## The following provide access from common developer platforms, to accelerate AEM Headless access to WKND content.
        # Developer Localhost
        SetEnvIfExpr "env('CORSProcessing') == 'true' && req_novary('Origin') =~ m#(http://localhost(:\d+)?$)#" CORSTrusted=true
        # Adobe AppBuilder
        SetEnvIfExpr "env('CORSProcessing') == 'true' && req_novary('Origin') =~ m#(https://experience\.adobe\.com$)#" CORSTrusted=true          
        # Developer Vercel app
        SetEnvIfExpr "env('CORSProcessing') == 'true' && req_novary('Origin') =~ m#(https://.*\.vercel\.app$)#" CORSTrusted=true
        # Developer Github.io app
        SetEnvIfExpr "env('CORSProcessing') == 'true' && req_novary('Origin') =~ m#(https://.*\.github\.io$)#" CORSTrusted=true
        # Developer Codesandbox.io app
        SetEnvIfExpr "env('CORSProcessing') == 'true' && req_novary('Origin') =~ m#(https://.*\.csb\.app$)#" CORSTrusted=true
        # Developer CodePen.io app
        SetEnvIfExpr "env('CORSProcessing') == 'true' && req_novary('Origin') =~ m#(https://cdpn\.io$)#" CORSTrusted=true
 
        # EDS site Dev and Prod sites
        SetEnvIfExpr "env('CORSProcessing') == 'true' && req_novary('Origin') =~ m#(https://.*wkkellogg\.hlx\.live$)#" CORSTrusted=true
        SetEnvIfExpr "env('CORSProcessing') == 'true' && req_novary('Origin') =~ m#(https://.*wkkellogg\.aem\.live$)#" CORSTrusted=true
 
        # WKKC EDS sites
        SetEnvIfExpr "env('CORSProcessing') == 'true' && req_novary('Origin') =~ m#(https://.*wkkellogg\.com$)#" CORSTrusted=true
        SetEnvIfExpr "env('CORSProcessing') == 'true' && req_novary('Origin') =~ m#(https://.*wkkellogg\.ca$)#" CORSTrusted=true
        SetEnvIfExpr "env('CORSProcessing') == 'true' && req_novary('Origin') =~ m#(https://.*ricekrispies\.com$)#" CORSTrusted=true
        SetEnvIfExpr "env('CORSProcessing') == 'true' && req_novary('Origin') =~ m#(https://.*ricekrispies\.ca$)#" CORSTrusted=true
        SetEnvIfExpr "env('CORSProcessing') == 'true' && req_novary('Origin') =~ m#(https://.*frostedflakes\.com$)#" CORSTrusted=true
        SetEnvIfExpr "env('CORSProcessing') == 'true' && req_novary('Origin') =~ m#(https://.*missiontiger\.com$)#" CORSTrusted=true
        SetEnvIfExpr "env('CORSProcessing') == 'true' && req_novary('Origin') =~ m#(https://.*specialk\.com$)#" CORSTrusted=true
        SetEnvIfExpr "env('CORSProcessing') == 'true' && req_novary('Origin') =~ m#(https://.*specialk\.ca$)#" CORSTrusted=true
        SetEnvIfExpr "env('CORSProcessing') == 'true' && req_novary('Origin') =~ m#(https://.*kashi\.com$)#" CORSTrusted=true
        SetEnvIfExpr "env('CORSProcessing') == 'true' && req_novary('Origin') =~ m#(https://.*kashi\.ca$)#" CORSTrusted=true
        SetEnvIfExpr "env('CORSProcessing') == 'true' && req_novary('Origin') =~ m#(https://.*wkkelloggawayfromhome\.com$)#" CORSTrusted=true
 
        ################## END EDITABLE SECTION
 
        # Extract the Origin header
        SetEnvIfNoCase ^Origin$ ^(.*)$ CORSTrustedOrigin=$1
 
        # Flush If already set
        Header unset Access-Control-Allow-Origin
        Header unset Access-Control-Allow-Credentials
 
        # Trusted
        Header always set Access-Control-Allow-Credentials "true" "expr=reqenv('CORSTrusted') == 'true'"
        Header always set Access-Control-Allow-Origin "%{CORSTrustedOrigin}e" "expr=reqenv('CORSTrusted') == 'true'"
        Header always set Access-Control-Allow-Methods "GET" "expr=reqenv('CORSTrusted') == 'true'"
        Header always set Access-Control-Max-Age 1800 "expr=reqenv('CORSTrusted') == 'true'"
        Header always set Access-Control-Allow-Headers "Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers" "expr=reqenv('CORSTrusted') == 'true'"
 
        # Uncomment while debugging
        # Header always set Debug-CORSProcessing "true" "expr=reqenv('CORSProcessing') == 'true'"
        # Header always set Debug-CORSProcessing "false" "expr=reqenv('CORSProcessing') == 'false'"
        # Header always set Debug-CORSTrusted "false" "expr=reqenv('CORSTrusted') == 'false'"
        # Header always set Debug-CORSTrusted "true" "expr=reqenv('CORSTrusted') == 'true'"
 
        # Non-CORS or Not Trusted
        Header unset Access-Control-Allow-Credentials "expr=reqenv('CORSProcessing') == 'false' || reqenv('CORSTrusted') == 'false'"
        Header unset Access-Control-Allow-Origin "expr=reqenv('CORSProcessing') == 'false' || reqenv('CORSTrusted') == 'false'"
        Header unset Access-Control-Allow-Methods "expr=reqenv('CORSProcessing') == 'false' || reqenv('CORSTrusted') == 'false'"
        Header unset Access-Control-Max-Age "expr=reqenv('CORSProcessing') == 'false' || reqenv('CORSTrusted') == 'false'"
 
        # Always vary on origin, even if its not there.
        Header merge Vary Origin
 
        # CORS - send 204 for CORS requests which are not trusted
        RewriteCond expr "reqenv('CORSProcessing') == 'true' && reqenv('CORSTrusted') == 'false'"
        RewriteRule "^(.*)" - [R=204,L]
 
        # Remove Origin before sending to AEM Publish
        RequestHeader unset Origin
 
        ################## End of CORS configuration ##################
 
# Content Security Policies for wkkellogg.com
 
# Match specific domains
# SetEnvIfExpr "%{HTTP_HOST} == 'dev.wkkellogg.com' || %{HTTP_HOST} == 'www.wkkellogg.com'" is_wkkellogg
 
# Apply CSP header only for matched domains
 
 
</IfModule>
<Directory />
<IfModule disp_apache2.c>
# Some items cache with the wrong mime type
# Use this option to use the name to auto-detect mime types when cached improperly
ModMimeUsePathInfo On
# Use this option to avoid cache poisioning
# Sling will return /content/image.jpg as well as /content/image.jpg/ but apache can't search /content/image.jpg/ as a file
# Apache will treat that like a directory.  This assures the last slash is never stored in cache
DirectorySlash Off
# Enable the dispatcher file handler for apache to fetch files from AEM
SetHandler dispatcher-handler
</IfModule>
Options FollowSymLinks
AllowOverride None
# Insert filter
SetOutputFilter DEFLATE
# Don't compress images
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ no-gzip dont-vary
# Prevent clickjacking
Header always append X-Frame-Options SAMEORIGIN
</Directory>
<Directory "${DOCROOT}">
AllowOverride None
Require all granted
</Directory>
<IfModule disp_apache2.c>
# Enabled to allow rewrites to take affect and not be ignored by the dispatcher module
DispatcherUseProcessedURL On
# Default setting to allow all errors to come from the aem instance
DispatcherPassError 0
</IfModule>
<IfModule mod_rewrite.c>
RewriteEngine on
Include conf.d/rewrites/rewrite.rules
 
# Rewrite index page internally, pass through (PT)
RewriteRule "^(/?)$" "/index.html" [PT]
 
</IfModule>
    
    # Removing Content-Disposition to make the robots.txt render instead of downloading in browser
    <Location "/content/dam/wkkellogg/robots.txt">
        Header unset Content-Disposition
    </Location>
</VirtualHost>

 

 

 

 

 

 

 

 

 


@VeenaVi 
Thanks and Regards,
Prashanth M

Topics

Topics help categorize Community content and increase your ability to discover relevant content.

4 Replies

Avatar

Community Advisor

Hi @ragavmer,

Can you try

  • Adding a dummy header like Header always set X-Test-Header "Working" without any env=. Deploy and check if it appears in the response.

    I would avoid env= for testing

    • Temporarily remove env=IS_WKKELOGG and just try:
      Header always set Content-Security-Policy "default-src 'self'; ..."

       

      Also, Add another visible test header (X-Vhost) to confirm request is not bypassing dispatcher.
      • If your domain is using Fastly (default CDN for AEMaaCS), it may override or strip security headers.

      • Use tools like curl -I or browser DevTools → Network → Response Headers to validate headers at different layers.

         

        I would recommend to Simplify the header and remove env= for testing:

        <IfModule mod_headers.c>
            Header always set Content-Security-Policy "default-src 'self'; script-src 'self' https://example.com;" 
        </IfModule>

        Then redeploy and validate using:

        curl -I https://your-site.com
        Use SetEnvIf correctly (alternative to SetEnvIfExpr)

        Your current usage:

        SetEnvIfExpr "%{HTTP_HOST} == 'www.abc.com'" IS_WKKELOGG

        Sometimes doesn’t work as expected in Cloud setup. Instead, try:

        SetEnvIf Host "www\.abc\.com" IS_WKKELOGG

        Then:

         Header always set Content-Security-Policy "..." env=IS_WKKELOGG

Santosh Sai

AEM BlogsLinkedIn


Avatar

Level 1

Hi @SantoshSai 
I tried adding dummy Header for debugging 

Header always set X-Test-Header "Working"  

it also did not come in response header ( did not work) 

same Vhost is being used for multiple domains 

I have the doubt whether the vhost is being pikked or not ? 
I haved added one more < virtulahost > in the same vhost and mentioned 
servername as "http.example.com "
then also not working , 

am not able understand the issue , please share your inputs 

#
# This is the default publish virtualhost definition for Apache. 
#
# DO NOT EDIT this file, your changes will have no impact on your deployment.
#
# Instead create a copy in the folder conf.d/available_vhosts and edit the copy.
# Finally, change to the directory conf.d/enabled_vhosts, remove the symbolic
# link for default.vhost and create a symbolic link to your copy.
#
 
# Include customer defined variables
Include conf.d/variables/custom.vars
 
<VirtualHost *:80>
ServerName "publish"
# Put names of which domains are used for your published site/content here
ServerAlias "*"
# Use a document root that matches the one in conf.dispatcher.d/default.farm
DocumentRoot "${DOCROOT}"
# URI dereferencing algorithm is applied at Sling's level, do not decode parameters here
AllowEncodedSlashes NoDecode
# Add header breadcrumbs for help in troubleshooting
 
<IfModule mod_headers.c>
Header add X-Vhost "publish"
 
# SetEnvIfExpr "%{HTTP_HOST} == 'www.wkkellogg.com'" IS_WKKELOGG
# Match any subdomain of wkkellogg.com
# Match any subdomain of kashi.com
# SetEnvIf Host "^[^.]+\.kashi\.com$" IS_KASHI
# Apply CSP for WK Kellogg
# Header set Content-Security-Policy "default-src 'self'; script-src 'self' https://*.wkkellogg.com;" env=IS_WKKELOGG
# Apply CSP for Kashi
# Header set Content-Security-Policy "default-src 'self'; script-src 'self' https://*.kashi.com;" env=IS_KASHI
 
################## Start of CORS configuration ##################
 
        
       
        # Extract the Origin header
        SetEnvIfNoCase ^Origin$ ^(.*)$ CORSTrustedOrigin=$1
 
        # Flush If already set
        Header unset Access-Control-Allow-Origin
        Header unset Access-Control-Allow-Credentials
 
        # Trusted
        Header always set Access-Control-Allow-Credentials "true" "expr=reqenv('CORSTrusted') == 'true'"
        Header always set Access-Control-Allow-Origin "%{CORSTrustedOrigin}e" "expr=reqenv('CORSTrusted') == 'true'"
        Header always set Access-Control-Allow-Methods "GET" "expr=reqenv('CORSTrusted') == 'true'"
        Header always set Access-Control-Max-Age 1800 "expr=reqenv('CORSTrusted') == 'true'"
        Header always set Access-Control-Allow-Headers "Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers" "expr=reqenv('CORSTrusted') == 'true'"
 
       
 
 
</IfModule>
<Directory />
<IfModule disp_apache2.c>
# Some items cache with the wrong mime type
# Use this option to use the name to auto-detect mime types when cached improperly
ModMimeUsePathInfo On
# Use this option to avoid cache poisioning
# Sling will return /content/image.jpg as well as /content/image.jpg/ but apache can't search /content/image.jpg/ as a file
# Apache will treat that like a directory.  This assures the last slash is never stored in cache
DirectorySlash Off
# Enable the dispatcher file handler for apache to fetch files from AEM
SetHandler dispatcher-handler
</IfModule>
Options FollowSymLinks
AllowOverride None
# Insert filter
SetOutputFilter DEFLATE
# Don't compress images
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ no-gzip dont-vary
# Prevent clickjacking
Header always append X-Frame-Options SAMEORIGIN
</Directory>
<Directory "${DOCROOT}">
AllowOverride None
Require all granted
</Directory>
<IfModule disp_apache2.c>
# Enabled to allow rewrites to take affect and not be ignored by the dispatcher module
DispatcherUseProcessedURL On
# Default setting to allow all errors to come from the aem instance
DispatcherPassError 0
</IfModule>
<IfModule mod_rewrite.c>
RewriteEngine on
Include conf.d/rewrites/rewrite.rules
 
# Rewrite index page internally, pass through (PT)
RewriteRule "^(/?)$" "/index.html" [PT]
 
</IfModule>
    
    # Removing Content-Disposition to make the robots.txt render instead of downloading in browser
    <Location "/content/dam/wkkellogg/robots.txt">
        Header unset Content-Disposition
    </Location>
</VirtualHost>
<VirtualHost *:80>
ServerName "dev.wkkellogg.com"
# Put names of which domains are used for your published site/content here
 
# Use a document root that matches the one in conf.dispatcher.d/default.farm
DocumentRoot "${DOCROOT}"
# URI dereferencing algorithm is applied at Sling's level, do not decode parameters here
AllowEncodedSlashes NoDecode 
# Add header breadcrumbs for help in troubleshooting
 
<IfModule mod_headers.c>
Header add X-Vhost "publish"
 
# Apply CSP for WK Kellogg
 
</IfModule>
<Directory />
<IfModule disp_apache2.c>
# Some items cache with the wrong mime type
# Use this option to use the name to auto-detect mime types when cached improperly
ModMimeUsePathInfo On
# Use this option to avoid cache poisioning
# Sling will return /content/image.jpg as well as /content/image.jpg/ but apache can't search /content/image.jpg/ as a file
# Apache will treat that like a directory.  This assures the last slash is never stored in cache
DirectorySlash Off
# Enable the dispatcher file handler for apache to fetch files from AEM
SetHandler dispatcher-handler
</IfModule>
Options FollowSymLinks
AllowOverride None
# Insert filter
SetOutputFilter DEFLATE
# Don't compress images
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ no-gzip dont-vary
# Prevent clickjacking
Header always append X-Frame-Options SAMEORIGIN
</Directory>
<Directory "${DOCROOT}">
AllowOverride None
Require all granted
</Directory>
<IfModule disp_apache2.c>
# Enabled to allow rewrites to take affect and not be ignored by the dispatcher module
DispatcherUseProcessedURL On
# Default setting to allow all errors to come from the aem instance
DispatcherPassError 0
</IfModule>
<IfModule mod_rewrite.c>
RewriteEngine on
Include conf.d/rewrites/rewrite.rules
 
# Rewrite index page internally, pass through (PT)
RewriteRule "^(/?)$" "/index.html" [PT]
 
</IfModule>
    
    # Removing Content-Disposition to make the robots.txt render instead of downloading in browser
    <Location "/content/dam/wkkellogg/robots.txt">
        Header unset Content-Disposition
    </Location>
</VirtualHost>



Thanks for quick response @SantoshSai and waiting for your inputs again 

regards, 
Prashanth 














Avatar

Level 5

Hi @Appsu2 

 

ServerAlias "*" 

please set this to exact server name of your website like dev.example.com

it shoult start picking this up and make sure the reference of this vhost is present in the enable_vhost folder

 

if any other vhost file contains ServerAlias as * or that url it will pick it up. in order to make sure it picks the new one, keep the name of the file as a_example so that its first alphabetically.

 

Also please check if there are any CDN rules which are removing all the headers.

Avatar

Community Advisor

@ragavmer Try below

 

<IfModule mod_headers.c>
Header always set Content-Security-Policy "upgrade-insecure-requests; frame-ancestors 'self' http://localhost https://localhost; default-src * data: 'self' 'unsafe-eval' 'unsafe-inline' blob: https: http:; object-src 'none'; script-src 'self' 'unsafe-eval' 'unsafe-inline' blob: https: http:; script-src-elem 'self' 'unsafe-eval' 'unsafe-inline' blob: https: http:; worker-src 'self' 'unsafe-eval' 'unsafe-inline' blob: data: https: http:; child-src 'self' 'unsafe-eval' 'unsafe-inline' blob: https: http:; base-uri 'self';"
</IfModule>