Gzip, Headers de Segurança e CORS
Aula 5 de 6
Compressão com Gzip
Configuração Básica
# No bloco http (nginx.conf)
gzip on;
gzip_comp_level 6;
gzip_min_length 1000;
gzip_proxied any;
gzip_vary on;
gzip_disable "msie6";
gzip_types
text/plain
text/css
text/xml
text/javascript
application/javascript
application/json
application/xml
application/rss+xml
application/atom+xml
image/svg+xml
font/ttf
font/opentype
application/vnd.ms-fontobject;
Gzip Static (arquivos pré-compactados)
gzip -k style.css
gzip -k -9 script.js
find /var/www/site/public -type f \( -name "*.css" -o -name "*.js" -o -name "*.html" \) -exec gzip -k {} \;
gzip_static on;
Gunzip (descompressão)
gunzip on;
location / {
gunzip on;
proxy_pass http://backend;
}
Minificação + Gzip
sudo npm install -g uglify-js clean-css-cli
uglifyjs script.js -o script.min.js -c -m
cleancss -o style.min.css style.css
gzip -k -9 script.min.js style.min.css
Headers de Segurança
Configuração Completa
server {
listen 443 ssl http2;
server_name site.exemplo.com;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
add_header Content-Security-Policy "
default-src 'self';
script-src 'self' https://analytics.exemplo.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https://cdn.exemplo.com;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' https://api.exemplo.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
" always;
}
Headers por Tipo de Conteúdo
location ~ \.html$ {
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
}
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff2?|ttf)$ {
expires 1y;
add_header Cache-Control "public, immutable";
add_header X-Content-Type-Options "nosniff";
access_log off;
}
location ~* \.(pdf|doc|docx|xls|xlsx|zip|tar|gz)$ {
add_header Content-Disposition "attachment";
expires 1d;
}
CORS (Cross-Origin Resource Sharing)
CORS Básico para API
server {
listen 80;
server_name api.exemplo.com;
location / {
add_header Access-Control-Allow-Origin "*" always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "Content-Type, Authorization, X-Requested-With" always;
add_header Access-Control-Expose-Headers "X-RateLimit-Remaining, X-RateLimit-Reset" always;
add_header Access-Control-Max-Age 86400 always;
if ($request_method = OPTIONS) {
add_header Content-Length 0;
add_header Content-Type text/plain;
return 204;
}
proxy_pass http://backend;
}
}
CORS Restrito para Domínios Específicos
map $http_origin $cors_origin {
default "";
~^https?://(www\.)?meusite\.com$ $http_origin;
~^https?://app\.meusite\.com$ $http_origin;
~^https?://admin\.meusite\.com$ $http_origin;
}
map $request_method $cors_methods {
OPTIONS "GET, POST, PUT, DELETE, OPTIONS, PATCH";
default "";
}
server {
location /api/ {
if ($cors_origin) {
add_header Access-Control-Allow-Origin "$cors_origin" always;
add_header Access-Control-Allow-Methods "$cors_methods" always;
add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
add_header Access-Control-Allow-Credentials "true" always;
add_header Access-Control-Max-Age 86400;
}
if ($request_method = OPTIONS) {
add_header Content-Length 0;
add_header Content-Type text/plain;
return 204;
}
proxy_pass http://backend;
}
}
Autenticação Básica (auth_basic)
sudo apt install apache2-utils -y
sudo htpasswd -c /etc/nginx/.htpasswd admin
sudo htpasswd /etc/nginx/.htpasswd usuario2
location /admin {
auth_basic "Area Restrita";
auth_basic_user_file /etc/nginx/.htpasswd;
}
location /admin {
satisfy any;
allow 192.168.1.0/24;
deny all;
auth_basic "Area Restrita";
auth_basic_user_file /etc/nginx/.htpasswd;
}
Autenticação com auth_request
upstream auth_service {
server auth.exemplo.com:8080;
}
server {
location /protected {
auth_request /auth;
auth_request_set $auth_status $upstream_status;
error_page 401 = @error401;
proxy_pass http://backend;
}
location = /auth {
internal;
proxy_pass http://auth_service/validate;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Original-Method $request_method;
}
location @error401 {
return 302 https://auth.exemplo.com/login?redirect=$request_uri;
}
}
Módulo real_ip
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
real_ip_header CF-Connecting-IP;
Lab: Site Seguro com Gzip e Headers
# 1. Criar estrutura do site
sudo mkdir -p /var/www/secure-site/{public,api}
echo "<h1>Headers de Seguranca Ativos</h1>" | sudo tee /var/www/secure-site/public/index.html
echo "body { font-family: sans-serif; }" | sudo tee /var/www/secure-site/public/style.css
echo "console.log('Seguro');" | sudo tee /var/www/secure-site/public/script.js
# 2. Pre-comprimir assets
gzip -k /var/www/secure-site/public/style.css
gzip -k /var/www/secure-site/public/script.js
# 3. Criar configuracao
cat << 'EOF' | sudo tee /etc/nginx/sites-available/secure-headers
gzip on;
gzip_comp_level 6;
gzip_min_length 256;
gzip_vary on;
gzip_proxied any;
gzip_types text/plain text/css application/javascript application/json image/svg+xml;
gzip_static on;
server {
listen 80;
server_name secure-headers.local;
root /var/www/secure-site/public;
index index.html;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self'; img-src 'self';" always;
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
location ~ \.html$ {
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
location /api/ {
add_header Access-Control-Allow-Origin "*" always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
add_header Access-Control-Max-Age 86400 always;
if ($request_method = OPTIONS) {
add_header Content-Length 0;
add_header Content-Type text/plain;
return 204;
}
proxy_pass http://127.0.0.1:3000;
}
location /admin {
auth_basic "Admin Access";
auth_basic_user_file /etc/nginx/.htpasswd;
}
access_log /var/log/nginx/secure-headers-access.log;
error_log /var/log/nginx/secure-headers-error.log;
}
EOF
# 4. Criar senha admin
sudo htpasswd -c /etc/nginx/.htpasswd admin
# 5. Habilitar site
sudo ln -sf /etc/nginx/sites-available/secure-headers /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx
# 6. Testar headers
curl -I http://secure-headers.local/ | grep -E "X-|Content-Security|Referrer"
curl -H "Accept-Encoding: gzip" -I http://secure-headers.local/style.css | grep -E "Content-Encoding|Vary"
curl -I http://secure-headers.local/api/ | grep -i access-control
Seguranca no Nginx e construida em camadas: compressao (gzip), headers protetivos (CSP, HSTS, X-Frame-Options), CORS controlado e autenticacao. Cada header adiciona uma barreira contra classes especificas de ataque.