I have a spring boot app running on AWS that uploads a file to S3 which works fine for 1KB txt file. It fails for a 250KB txt with 403 Forbidden
with out any logs on the nginx access/error logs, request doesn't reach Tomcat as well. I even removed saving to disk/S3, as below. It immediatly fails with 403 Forbidden.
Controller
@GetMapping("/inputuploads")
public String listInputUploads(Model model) {
logger.info("Renedering upload page");
return "inputuploads";
}
@PostMapping("/inputuploads")
public String saveFile(Model model, @RequestParam("file") MultipartFile file, RedirectAttributes ra) throws IOException {
logger.info("Saving file:"+file.getOriginalFilename());
ra.addFlashAttribute("message","Uploaded file: "+ file.getOriginalFilename());
return "redirect:/inputuploads";
}
template
<div th:if="${message}">
<div th:text="${message}">
</div>
</div>
<div >
<form method="post" th:action="@{/inputuploads}" enctype="multipart/form-data" >
<div>
<input type="file" name="file" accept=".xlsm" >
</div>
<div>
<button type="submit" >Upload</button>
</div>
</form>
</div>
application.yml
spring:
servlet:
multipart:
max-file-size: 100MB
max-request-size: 100MB
server:
port: 5000
tomcat:
max-swallow-size: -1
.platform/nginx/nginx.conf
user nginx;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
worker_processes auto;
worker_rlimit_nofile 32633;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
include conf.d/*.conf;
map $http_upgrade $connection_upgrade {
default "upgrade";
}
server {
listen 80;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl default_server;
ssl_certificate certificates/localhost.crt;
ssl_certificate_key certificates/localhost.key;
access_log /var/log/nginx/access.log main;
client_header_timeout 1d;
client_body_timeout 1d;
client_max_body_size 100M;
keepalive_timeout 1d;
proxy_connect_timeout 1d;
proxy_read_timeout 1d;
proxy_send_timeout 1d;
gzip off;
gzip_comp_level 4;
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
include conf.d/elasticbeanstalk/*.conf;
}
}
.platform/nginx/conf.d/client_max_body_size.conf
client_max_body_size 100M;
.platform/nginx/conf.d/elasticbeanstalk/00_application.conf
location / {
proxy_pass http://127.0.0.1:5000;
proxy_http_version 1.1;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
.ebextensions/00-set-timezone.config
commands:
set_time_zone:
command: ln -f -s /usr/share/zoneinfo/Asia/Kolkata /etc/localtime
Since the HTTP requests don't get nginx
(expect for the small ones) and the error is 403 Forbidden
, it seems that AWS WAF (which can be attached to the frontend you are using, i.e. AWS ALB) is blocking the requests. By default, AWS WAF blocks requests if the HTTP body size is greater than 8 KB. You can change this behavior by configuring Oversize body handling.
So in this case, you can add a rule to the WAF ACL to specifically exclude the URI used for uploads. From Guidelines for managing oversize components in your web ACL:
If you need to allow some requests with oversize component contents, if possible, add rules to explicitly allow only those requests. Prioritize those rules so that they run before any other rules in the web ACL that inspect the same component types. With this approach, you won't be able to use AWS WAF to inspect the entire contents of the oversize components that you allow to pass to your protected resource.