I want to handle cors on nginx unit level but I don't know how it make on nginx unit.
Example config for nginx
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, OPTIONS, DELETE, PATCH';
add_header 'Access-Control-Allow-Headers' 'Authorization,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range';
add_header 'Access-Control-Expose-Headers' 'Gc-Export-Errors';
return 204;
}
How I can do this for nginx unit?
Currently, Nginx Unit doesn't support functionality equal to add_header so if you need custom headers for 204 response it should be done using application. And configuration will looks like this:
{
"match":{
"method": "OPTIONS"
},
"action":{
"proxy": "path/to/app_return_204_with_custom_headers"
}
}
Related
I'm trying to send a post request from a client-side javascript (fetch) to my server which uses Nginx as the web server. The client-side javascript runs on a different domain.
I'm having trouble configuring Nginx to reply with the proper headers, when I try the config below, I get a 405 Not Allowed on the preflight request:
location /cookie/ {
root /myPlace;
add_header Allow 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Origin' '$http_origin' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
index index.php;
}
When I try the configuration below, the preflight is successful and it contains all the headers needed for CORS, but the main request errors to MissingAllowOriginHeader the console error is the familiar No 'Access-Control-Allow-Origin' header is present on the requested resource.
Here is the config which results in the behavior described above:
location /cookie/ {
root /myPlace;
add_header Allow 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Origin' '$http_origin' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
add_header 'Access-Control-Allow-Origin' '$http_origin' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-headers' 'Content-Type' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
return 204;
}
index index.php;
}
The strange thing is that the main request in this case doesn't return any CORS headers, although the preflight has all the necessary headers and doesn't error out.
Any idea how can I get past these CORS errors
If it helps, this is the javascript code I use on the client-side:
let theData = {
id: "123",
};
fetch("https://myServer.com/cookie/", {
method: 'POST',
mode: 'cors',
cache: 'no-cache',
headers: {
'Content-Type': 'application/json'
},
redirect: 'follow',
body: JSON.stringify(theData),
});
Thank you
I use django-cors-headers 3.1.1 for handling the requests and responses between my Django-backend and Javascript-frontend apps. Transport is non-secured (i.e. http, not https).
When hosted locally, everything works fine. But after deploying on the server, I stopped seeing the CORS headers.
Here are headers in development:
and in production:
Error message:
Access to XMLHttpRequest at 'http://[HOST_IP]/api/assets/' from origin 'http://my_custom_domain.eu' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
My nginx configurations looks as follows:
server {
listen 80;
server_name [HOST_IP];
location / {
include proxy_params;
proxy_pass http://unix:/home/ubuntu/[path_to_app]/app.sock;
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, PUT, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Max-Age' 86400;
if ($request_method = 'OPTIONS') {
add_header 'Content-Type' 'text/html; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'PUT') {
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
}
location /static/ {
autoindex on;
alias /home/ubuntu/[path_to_app]/site/static/;
}
}
The django-cors-headers’ settings are now identical in development and in production:
INSTALLED_APPS = (
…
"corsheaders",
…
)
MIDDLEWARE = [
…
"corsheaders.middleware.CorsMiddleware",
"django.middleware.common.CommonMiddleware",
…
]
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_METHODS = ['DELETE','GET','OPTIONS','PATCH','POST','PUT']
On the client side I tried to add ‘'Access-Control-Request-Method’: ‘PUT’ header, but this was refused by the browser. There’s noting unusual in the client call:
axios({
method: 'put',
url: `${this.backendUrl}/api/assets/`,
data: formData,
headers: {
'Content-Type': 'application/octet-stream',
}
})
Also, I’m trying to host on the Amazon AWS EC2 for the first time, so perhaps there is some required AWS configuration I am not aware of. For example, is it necessary to enable CORS using the API Gateway? The documentation does not say so (‘If you are using the API Gateway Import API, you can set up CORS support using an OpenAPI file’).
The frontend application is hosted on a S3 bucket with the following CORS policy:
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>PUT</AllowedMethod>
<AllowedMethod>POST</AllowedMethod>
<AllowedMethod>GET</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
What am I missing here? Is there some needed server-side (nginx especially) configuration?
Some other solutions I’ve tried:
I have doubts, whether the request/response origin is correct (e.g. APPEND_SLASH variable). But if this is the case, shouldn’t an error be raised when hosted locally?
I also tried setting proxy headers as in this question, but without knowing nginx very well this was doomed to fail.
I managed to solve this issue by changing 3 things:
AWS
I noticed that AWS documentation states:
CORS is already enabled for the Amazon EC2 API, and is ready for you
to use. You do not need to perform any additional configuration steps
to start using this feature. There is no change to the way that you
make calls to the Amazon EC2 API; they must still be signed with valid
AWS credentials to ensure that AWS can authenticate the requestor. […]
This is usually handled by AWS SDK or CLI, but in my case I used none of them, so I had to add AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY. In my case I simply used aws4 library:
axios(aws4.sign({
accessKeyId: this.awsAccessKey,
secretAccessKey: this.awsSecretAccessKey,
method: 'put',
url: `${this.backendUrl}/api/assets/`,
data: formData,
body: JSON.stringify(formData),
service: 'ec2',
region: 'eu-central-1',
path: '/',
headers: {
'Content-Type': 'application/octet-stream'
}
}))
I’ve seen plenty of examples how to add AWS Signature v.4 without any additional dependency, though.
NGINX
In nginx configuration I placed all add_headers statements into conditional code-blocks. Idea came from this post.
server {
listen 80;
server_name [HOST_IP];
location / {
include proxy_params;
proxy_pass http://unix:/home/ubuntu/[path_to_app]/app.sock;
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, PUT, OPTIONS, POST, DELETE';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,X-Amz-Date';
add_header 'Access-Control-Max-Age' 86400;
add_header 'Content-Type' 'text/html; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'PUT') {
add_header 'Access-Control-Allow-Methods' 'GET, PUT, OPTIONS, POST, DELETE';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,X-Amz-Date';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, PUT, OPTIONS, POST, DELETE';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,X-Amz-Date';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
}
location /static/ {
autoindex on;
alias /home/ubuntu/analizy/be/site/static/;
}
}
Django-cors-header
Here it sufficed to add non-default headers.
from corsheaders.defaults import default_headers
CORS_ALLOW_HEADERS = list(default_headers) + [
'X-Amz-Date',
]
Hope that this will help someone.
I'm working on a project where we're hosting a webpage on AWS. The webpage calls a webAPI from a local area network computer name IE: Server-24.Local.
This approach ensures data doesn't leave the network as Server-24.Local is not exposed to the internet.
This approach has worked well so far. However, I am facing issues when i enable HTTPS via certbot:
If i try proxy_pass nginx to a webapi hosted in AWS on localhost, HTTPS works fine.
However, if i proxy_pass nginx to Server-24.Local, it returns cross-origin errors.
Both webAPIs are CORS-enabled.
Might anyone have any suggestions?
you can research about Nginx CORS enabled in internet... It's about end user browser security in chrome etc...
Here is an example, put it inside location tag {}
#
# Wide-open CORS config for nginx
#
location / {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
#
# Custom headers and headers various browsers *should* be OK with but aren't
#
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
#
# Tell client that this pre-flight info is valid for 20 days
#
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
}
you can help look at here [https://enable-cors.org/server_nginx.html] ...
hopefully this help you...
The goal is for nginx server to pass a custom request header called X-PA-AUTH_TOKEN to the uwsgi server. Below is the server block in nginx.conf file.
server {
listen 9390 default_server;
server_name _;
location / {
include uwsgi_params;
uwsgi_pass_request_headers on;
uwsgi_pass unix:/run/uwsgi/irm.sock;
uwsgi_pass_header X-PA-AUTH_TOKEN;
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
#
# Custom headers and headers various browsers *should* be OK with but aren't
#
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,X-PA-AUTH_TOKEN';
#
# Tell client that this pre-flight info is valid for 20 days
#
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
add_header 'X-PA-AUTH_TOKEN' '0';
return 204;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,X-PA-AUTH_TOKEN';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range,X-PA-AUTH_TOKEN';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,X-PA-AUTH_TOKEN';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range,X-PA-AUTH_TOKEN';
}
}
}
The uwsgi server receives the conventional headers like 'Content-Type' just fine from the nginx server.
But, the uwsgi server is still not receiving the custom request header X-PA-AUTH_TOKEN from the nginx server when, for example, a POST request is made.
What am I doing wrong here?
I believe by default nginx marks headers with underscores (X-PA-AUTH_TOKEN) as invalid so they get blocked. You can either enable underscores_in_headers: on; in nginx config (docs here) or simply rename your header to be X-PA-AUTH-TOKEN.
Note however that if you enable underscores_in_headers, what you actually receive on the flask side will be renamed to X-Pa-Auth-Token, so i guess it's better to simply rename the header in the first place and not bother with nginx setting.
I am using local development server (on my computer) for frontend. Backend is located on another server and I sending requests from frontend to backend using CORS.
It works ok, but when I passing cookies from frontend, It passed incorrect: namely the csrf token is different from what is stored in cookies.
Examples:
Cookies on Chrome dev tools, Application tab: csrf_token: b2o3q06llj
Request headers:
As you can see, header Cookie is different from data viewed on Application tab. X-Csrf-Token is correct, but Cookie header is wrong. It must contain csrf_token which is available on Dev tools > Application > Storage > Cookies
CORS setup in Nginx config (remote server):
if ($request_method ~* "(GET|POST)") {
add_header 'Access-Control-Allow-Origin' 'http://192.168.1.127:3000' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range, X-Csrf-Token, Cache-Control' always;
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
}
# Preflighted requests
if ($request_method = OPTIONS ) {
add_header "Access-Control-Allow-Origin" 'http://192.168.1.127:3000' always;
add_header "Access-Control-Allow-Credentials" 'true' always;
add_header "Access-Control-Allow-Methods" "GET, POST, OPTIONS, HEAD" always;
add_header "Access-Control-Allow-Headers" "Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Csrf-Token, Cache-Control" always;
return 204;
}
Axios setup:
axios.create({
baseURL: window.location.protocol + '//' +window.location.hostname + (window.location.port ? ':' + window.location.port : '') + '/data',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-Csrf-Token': <token>,
'X-Requested-With': 'XMLHttpRequest'
},
withCredentials: true
});
I can not understand what the problem is. Why does axios not send correct cookies?