apache.htaccesscontent-security-policymod-headers

.htaccess Variables Issue Unrecognized header format %


I am building out a sort of Content Security Policy generator for one of my sites. I am stumped by one particular section of the .htaccess portion of it

The generated .htaccess is:

# Media Sources
SetEnv CSP_Media "media-src 'self' ;"

# Default Sources
SetEnv CSP_Default "default-src 'self' kevinpirnie.com ;"

# Add the CSP Headers
SetEnv CSP "%{ENV:CSP_Default} %{ENV:CSP_Media}"
Header always set Content-Security-Policy %{ENV:CSP}
Header always set X-Content-Security-Policy %{ENV:CSP}

When I leave the quotes off the SetEnv CSP line, I get a different error: SetEnv takes 1-2 arguments which makes sense... but with the quotes around them, I am getting the Unrecognized header format % error

Any ideas what I can do to utilize variables for this, or how to fix the header format issue?


Solution

  • There are a few issues here...

    SetEnv CSP "%{ENV:CSP_Default} %{ENV:CSP_Media}"
    

    This actually sets the CSP environment variable to the literal value %{ENV:CSP_Default} %{ENV:CSP_Media} - the CSP_Default and CSP_Media env vars are not expanded. AFAIK there is no way to reference env vars in the value argument of the SetEnv directive.

    You can use mod_rewrite (or SetEnvIfExpr - see below) instead to create this CSP env var that is the concatenation of two existing env vars, separated by a space.

    HOWEVER, SetEnv (mod_env) is processed too late in the request for mod_rewrite (which is processed very early) to be able to read these env vars. So you will need to use SetEnvIf (mod_setenvif) instead (or use mod_rewrite as well to set the initial env vars).

    For example:

    RewriteEngine On
    
    # Media Sources
    SetEnvIf ^ ^ "CSP_Media=media-src 'self' ;"
    
    # Default Sources
    SetEnvIf ^ ^ "CSP_Default=default-src 'self' kevinpirnie.com ;"
    
    # Add the CSP Headers
    RewriteRule ^ - "[E=CSP:%{ENV:CSP_Media} %{ENV:CSP_Default}]"
    

    Note the strategically placed double-quotes because the value argument contains spaces.

    UPDATE: You can avoid the use of mod_rewrite in the above and use the SetEnvIfExpr directive instead to concatenate the env vars using an Apache expression (Apache 2.4).

    For example:

    # Add the CSP Headers
    SetEnvIfExpr "reqenv('CSP_Media').' '.reqenv('CSP_Default') =~ /(.*)/" CSP=$1
    

    The dots (.) on the LHS of the expression are string concatenation operators (much like PHP). They do not appear as part of the string captured by the regex (RHS) and used as the concatenated value in the $1 backreference.

    Accessing the env var in the Header directive

    Header always set Content-Security-Policy %{ENV:CSP}
    Header always set X-Content-Security-Policy %{ENV:CSP}
    

    mod_headers uses a different syntax to access the value of env vars, hence the "Unrecognized header format %" error. You need to use %{var}e instead.

    For example:

    Header always set Content-Security-Policy %{CSP}e
    Header always set X-Content-Security-Policy %{CSP}e
    

    Alternatively, you can avoid mod_rewrite and mod_setenvif by not creating your intermediate CSP env var and just combine them in the Header directive.

    For example:

    # Media Sources
    SetEnv CSP_Media "media-src 'self' ;"
    
    # Default Sources
    SetEnv CSP_Default "default-src 'self' kevinpirnie.com ;"
    
    # Add the CSP Headers
    Header always set Content-Security-Policy "%{CSP_Media}e %{CSP_Default}e"
    Header always set X-Content-Security-Policy "%{CSP_Media}e %{CSP_Default}e"
    

    Because of the space, the value argument needs to be surrounded in double quotes.


    I am building out a sort of Content Security Policy generator for one of my sites.

    Although, if this code is "auto-generated"(?) then why not just generate the complete Header in a single step?