cancel
Showing results for 
Search instead for 
Did you mean: 

Community 7.0: Possible CSRF attack noted when asserting referer header

michaelzietlow
Confirmed Champ
Confirmed Champ

I have a fresh community7.0 installation via zip distribution and ansible.
When enable SSL in /etc/nginx/conf.d/, the alfresco orange login page loads securely (https),  but when I attempt to authenticate,  I see the following CSRF errors in alfresco.log.

 2021-06-21 15:01:47,561  ERROR [alfresco.web.site] [http-nio-8080-exec-10] javax.servlet.ServletException: Possible CSRF attack noted when asserting referer header 'https://alfresco.domain.com/share/page/'. Request: POST /share/page/dologin, FAILED TEST: Assert referer POST /share/page/dologin :: referer: 'https://alfresco.domain.com/share/page/' vs server & context: http://127.0.0.1:8080/ (string) or  (regexp)


Is this something I need to fix in nginx config, alfresco.properties, or web-extension xml?

/etc/nginx/conf.d/alfresco.conf: 

server {
    access_log  /var/log/alfresco/access.log;
    error_log /var/log/alfresco/error.log error;

        listen 443 ssl;
        listen [::]:443 ssl;
server_name alfresco.domain.com; ssl_certificate /etc/certs/server.crt; ssl_certificate_key /etc/certs/server.key; ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; client_max_body_size 0; set $allowOriginSite *; proxy_pass_request_headers on; proxy_pass_header Set-Cookie; # Protect access to SOLR APIs location ~ ^(/.*/service/api/solr/.*)$ {return 403;} location ~ ^(/.*/s/api/solr/.*)$ {return 403;} location ~ ^(/.*/wcservice/api/solr/.*)$ {return 403;} location ~ ^(/.*/wcs/api/solr/.*)$ {return 403;} location ~ ^(/.*/proxy/.*/api/solr/.*)$ {return 403 ;} location ~ ^(/.*/-default-/proxy/.*/api/.*)$ {return 403;} # Protect access to Prometheus endpoint location ~ ^(/.*/s/prometheus)$ {return 403;} location / { proxy_pass http://127.0.0.1:8080; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass_header Set-Cookie; proxy_set_header X-Forwarded-Proto https; } # External settings, do not remove #ENV_ACCESS_LOG location /share/ { proxy_pass http://127.0.0.1:8080; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass_header Set-Cookie; proxy_set_header X-Forwarded-Proto https; } location /alfresco/ { proxy_pass http://127.0.0.1:8080; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass_header Set-Cookie; proxy_set_header X-Forwarded-Proto https; } location /api-explorer/ { proxy_pass http://127.0.0.1:8080; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass_header Set-Cookie; proxy_set_header X-Forwarded-Proto https; } }
1 ACCEPTED ANSWER

Much thanks Afaust!

Here is my now working SSL configuration through haproxy, Nginx, and alfresco/content-services!

/etc/nginx/conf.d/alfresco.conf:

...snip...
listen 443 ssl;
listen [::]:443 ssl;
server_name alfresco.domain.com;
ssl_certificate /etc/certs/server.crt;
ssl_certificate_key /etc/certs/server.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;

...snip...

location /share/ {
proxy_pass http://127.0.0.1:8080;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_pass_header Set-Cookie;
proxy_set_header X-Forwarded-Proto https;

}

...snip...


/etc/opt/alfresco/content-services/classpath/alfresco-global.properties:

...snip...

# CSRF filter overrides
csrf.filter.enabled=true
csrf.filter.referer=^https?://alfresco\.domain\.com(/.*)?
csrf.filter.referer.always=false
csrf.filter.origin=^https?://alfresco\.domain\.com(/.*)?
csrf.filter.origin.always=false

...snip...


/etc/opt/alfresco/content-services/classpath/alfresco/web-extension/share-config-custom.xml:

...snip...
<properties> <!-- There is normally no need to override this property --> <token>Alfresco-CSRFToken</token> <!-- Override and set this property with a regexp that if you have placed Share behind a proxy that does not rewrite the Referer header. --> <referer>^https?://alfresco\.domain\.com(/.*)?</referer> <!-- Override and set this property with a regexp that if you have placed Share behind a proxy that does not rewrite the Origin header. --> <origin>^https?://alfresco\.domain\.com(/.*)?</origin> </properties>

...snip...

View answer in original post

4 REPLIES 4

afaust
Legendary Innovator
Legendary Innovator

This has not much do to with your nginx config. Rather your CSRF configuration in Alfresco is incomplete, missing the CSRF referrer / origin patterns for your public URL. In Share this is done via the share-config-custom.xml by setting the CSRFPolicy's origin/referrer sub-elements. In ACS Repository, this is done via alfresco-global.properties by setting the appropriate referrer/origin properties.

I tried setting "csrf.filter.enabled=false" in my global properties file with no success so I tried my best to add the needed settings to make it work but that also was unsuccessful.  😞 

My Environment is Community7 behind HAPROXY which then forwards the https traffic to NGINX which then forwards that to community7 on my private network. 

host1= HAPROXY:   https://alfresco.domain.com
host2= NGINX:         https://alfresco.dmz.domain.com
host2= ALFRESCO  http://127.0.0.1:8080/share


I have csrf.filter(s) set in my properties file

/etc/opt/alfresco/content-services/classpath/alfresco-global.properties:

...
# CSRF filter overrides csrf.filter.enabled=enabled csrf.filter.referer=https://alfresco.dmz.domain.com/.* csrf.filter.referer.always=false csrf.filter.origin=https://alfresco.dmz.domain.com csrf.filter.origin.always=false
...

HOWEVER,  I'm not familiar share-config-custom.xml syntax or positioning the CSRF settings in the correct location of the xml code. 

This is what I have uncommented out but I still see CSRF errors in my share.log...

/etc/opt/alfresco/content-services/classpath/alfresco/web-extension/share-config-custom.xml:

...

<!-- CSRF filter config to mitigate CSRF/Seasurfing/XSRF attacks To disable the CSRF filter override the <filter> to not contain any values, see share-config-custom.xml for an example. If you have a custom resource(s) that a client POST to that can't accept a token, for whatever reason, then make sure to copy the entire CSRFPolicy config and place it in your share-config-custom.xml file with the replace="true" attribute and make sure to add a new <rule> in the top of the <filter> element, which has a <request> element matching your requests, and uses only the "assertReferer" & "assertOrigin" actions. I.e.
--> <rule> <request> <method>POST</method> <path>/proxy/alfresco/custom/repoWebscript/withoutParams|/service/custom/shareResource/thatMayHaveParams(\?.+)?</path> </request> <action name="assertReferer"> <param name="referer">{referer}</param> </action> <action name="assertOrigin"> <param name="origin">{origin}</param> </action> </rule> <config evaluator="string-compare" condition="CSRFPolicy" replace="true"> <!-- Properties that may be used inside the rest of the CSRFPolicy config to avoid repetition but also making it possible to provide different values in different environments. I.e. Different "Referer" & "Origin" properties for test & production etc. Reference a property using "{propertyName}". --> <properties> <!-- There is normally no need to override this property --> <token>Alfresco-CSRFToken</token> <!-- Override and set this property with a regexp that if you have placed Share behind a proxy that does not rewrite the Referer header. --> <referer>alfresco.dmz.domain.com</referer> <!-- Override and set this property with a regexp that if you have placed Share behind a proxy that does not rewrite the Origin header. --> <origin>alfresco.dmz.domain.com</origin> </properties> <!-- Will be used and exposed to the client side code in Alfresco.contants.CSRF_POLICY. Use the Alfresco.util.CSRFPolicy.getHeader() or Alfresco.util.CSRFPolicy.getParameter() with Alfresco.util.CSRFPolicy.getToken() to set the token in custom 3rd party code. --> <client> <cookie>{token}</cookie> <header>{token}</header> <parameter>{token}</parameter> </client>

...

You need to set the public base URL that users will use as the referrer / origin in the CSRF policy section, so if they go through HAProxy, then that would be https://alfresco.domain.com. Note that technically, referrer and origin are regular expressions, so the technically correct values would be

https://alfresco\.domain\.com(/.*)?

Also note that you do not need to uncomment / use the whole CSRF policy section. It is completely sufficient to use

<config evaluator="string-compare" condition="CSRFPolicy" replace="true">
    <properties>
        <token>Alfresco-CSRFToken</token>
        <referer>https://alfresco\.domain\.com(/.*)?</referer>
        <origin>https://alfresco\.domain\.com(/.*)?</origin>
    </properties>
</config>

Much thanks Afaust!

Here is my now working SSL configuration through haproxy, Nginx, and alfresco/content-services!

/etc/nginx/conf.d/alfresco.conf:

...snip...
listen 443 ssl;
listen [::]:443 ssl;
server_name alfresco.domain.com;
ssl_certificate /etc/certs/server.crt;
ssl_certificate_key /etc/certs/server.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;

...snip...

location /share/ {
proxy_pass http://127.0.0.1:8080;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_pass_header Set-Cookie;
proxy_set_header X-Forwarded-Proto https;

}

...snip...


/etc/opt/alfresco/content-services/classpath/alfresco-global.properties:

...snip...

# CSRF filter overrides
csrf.filter.enabled=true
csrf.filter.referer=^https?://alfresco\.domain\.com(/.*)?
csrf.filter.referer.always=false
csrf.filter.origin=^https?://alfresco\.domain\.com(/.*)?
csrf.filter.origin.always=false

...snip...


/etc/opt/alfresco/content-services/classpath/alfresco/web-extension/share-config-custom.xml:

...snip...
<properties> <!-- There is normally no need to override this property --> <token>Alfresco-CSRFToken</token> <!-- Override and set this property with a regexp that if you have placed Share behind a proxy that does not rewrite the Referer header. --> <referer>^https?://alfresco\.domain\.com(/.*)?</referer> <!-- Override and set this property with a regexp that if you have placed Share behind a proxy that does not rewrite the Origin header. --> <origin>^https?://alfresco\.domain\.com(/.*)?</origin> </properties>

...snip...