Configuration: An unsecured backend (Sringboot 3) is deployed on a Tomcat 10 (java 17) server. The frontend (Angular 15) is deployed on an Apache 2.4 webserver.
The webserver also serves as a reverse proxy to circumvent the ban on making Ajax requests by the same origin security policy of Cross-Origin Resource Sharing (CORS). Without the reverse proxy, the backend is inaccessible by the frontend.
Http: This configuration works perfectly when the browser accesses the frontend via http.
Https: This configuration also works when the browser accesses the frontend in https for the execution of JavaScript code (Angular) and also when sending and processing the response returned by the webserver from 'GET' requests. On the other hand, when the frontend sends a 'POST' request to the webserver (apache), the webserver returns a 403 (forbidden). Here is what we see in the “network” tab of the browser (devtools):
Header :
Request URL:https://letstryfront.com/api/genjournallinespagedmultisort?page=0&size=10
Request Method:POST
Status Code:403 Forbidden
Remote Address:192.168.56.105:443
Referrer Policy:strict-origin-when-cross-origin
Response Header :
Connection:Keep-Alive
Content-Type:text/plain
Date:Fri, 29 Dec 2023 09:29:11 GMT
Keep-Alive:timeout=5, max=100
Server:Apache/2.4.58 (Unix) OpenSSL/3.2.0
Transfer-Encoding:chunked
Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate, br
Accept-Language:en-GB,en-US;q=0.9,en;q=0.8
Connection:keep-alive
Content-Length:2
Content-Type:application/json
Host:letstryfront.com
Origin:https://letstryfront.com
Referer:https://letstryfront.com/journal
Sec-Ch-Ua:"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"
Sec-Ch-Ua-Mobile:?0
Sec-Ch-Ua-Platform:"Windows"
Sec-Fetch-Dest:empty
Sec-Fetch-Mode:cors
Sec-Fetch-Site:same-origin
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
Surprisingly, when the 'POST' request is sent using curl, the webserver normally performs it with a 200 (success).
curl -X POST -v "https://letstryfront.com/api/genjournallinespagedmultisort?page=5&size=10" -H "accept: */*" -H "Content-Type: application/json" -d "[ { \"sortField\": \"lineno\", \"sortDirection\": \"asc\", \"orderSeq\": 0 }]" -o journallines.json --ssl-no-revoke
The tomcat10 logs show the “Completed 200 OK” but the 403 Forbidden are nowhere to be found.
The Apache webserver logs do, however, show a 403 return from the backend running on tomcat: Status from backend: 403, referer: https://letstryfront.com/journal
Here is the configuration of virtualhosts at the Apache server level:
<VirtualHost *:80>
ServerName letstryfront.com
ServerAlias *.letstryfront.com
SSLProxyEngine on
SSLProxyCheckPeerCN Off
SSLProxyCheckPeerName Off
SSLProxyVerify none
DocumentRoot "/srv/http/letstryfront"
<Directory /srv/http/letstryfront>
Options Indexes FollowSymLinks MultiViews
Allow from all
AllowOverride All
Require all granted
</Directory>
<LocationMatch "/api">
ProxyPreserveHost on
</LocationMatch>
ProxyPass /api http://localhost:8080/letstrysome/api
ProxyPassReverse /api http://localhost:8080/letstrysome/api
Proxypass /external/geocode/ https://maps.googleapis.com/maps/api/geocode/
ProxypassReverse /external/geocode/ https://maps.googleapis.com/maps/api/geocode/
Proxypass /external/v1/ https://api.open-meteo.com/v1/
ProxypassReverse /external/v1/ https://api.open-meteo.com/v1/
RewriteEngine On
RewriteCond %{REQUEST_URI}$1 external/geocode/json
RewriteCond %{QUERY_STRING} ^(address=.*&)key=.*$
RewriteRule ^ %{REQUEST_URI}?%1key=REMOVED [NE,PT,END]
LogLevel trace2
ErrorLog "/var/log/httpd/letstryfront.com-error_log"
CustomLog "/var/log/httpd/letstryfront.com-access_log" common
</VirtualHost>
<VirtualHost *:443>
ServerName letstryfront.com
ServerAlias 192.168.56.105 *.letstryfront.com
SSLEngine on
SSLCertificateFile /etc/ssl/certs/letstryfront.com.crt
SSLCertificateKeyFile /etc/ssl/private/letstryfront.com.key
SSLCACertificatePath /etc/ssl/certs/
SSLProxyEngine on
SSLProxyCheckPeerCN Off
SSLProxyCheckPeerName Off
SSLProxyVerify none
DocumentRoot "/srv/http/letstryfront"
<Directory /srv/http/letstryfront>
Options Indexes FollowSymLinks MultiViews
Allow from all
AllowOverride All
Require all granted
</Directory>
<LocationMatch "/api">
ProxyPreserveHost on
</LocationMatch>
ProxyPass /api http://localhost:8080/letstrysome/api
ProxyPassReverse /api http://localhost:8080/letstrysome/api
Proxypass /external/geocode/ https://maps.googleapis.com/maps/api/geocode/
ProxypassReverse /external/geocode/ https://maps.googleapis.com/maps/api/geocode/
Proxypass /external/v1/ https://api.open-meteo.com/v1/
ProxypassReverse /external/v1/ https://api.open-meteo.com/v1/
RewriteEngine On
RewriteCond %{REQUEST_URI}$1 external/geocode/json
RewriteCond %{QUERY_STRING} ^(address=.*&)key=.*$
RewriteRule ^ %{REQUEST_URI}?%1key=REMOVED [NE,PT,END]
LogLevel trace4
ErrorLog "/var/log/httpd/letstryfront.com-tls-error_log"
CustomLog "/var/log/httpd/letstryfront.com-tls-access_log" common
</VirtualHost>
I changed the https virtualhost configuration (443) several times. I suppose it is possible to force POST requests to pass. I'm still testing. Another solution could be to act at the backend level. If anyone has a solution, whether at the backend level (Springboot 3) of the Tomcat 10 server or the Apache 2.4 configuration, I would be interested.
I looked again at the log and noticed the header sent by curl is different that the one sent by the browser. So I added the
RequestHeader unset Origindirective to the https virtualhost configuration file. Now the https virtualhost configuration file looks like this:After this change I restarted the httpd service and now it's fine. Although this solution works, I was wondering if there is another method to solve the problem, at the backens level.