CORS and non 200 statusCode - nginx

I have CORS working well with Nginx. The APIs are designed to send non HTTP 200 status code, for example, 401, 404, etc., in case of bad input. The problem is that Chrome cancels/abort the request if it receives a non HTTP 200 status code. Due to this reason, I am not able to show the exact error on the Web client.
What is the way around for CORS non 200 status code errors?

By default Nginx only adds headers for requests it considers successful. You can make it add the header without regard for the response code, by adding the always parameter to your add_header directive, e.g.
add_header 'Access-Control-Allow-Origin' '*' always;
Adding the always parameter to the Access-Control-Allow-Origin header is not enough. The always parameter needs to be added to the headers that need to be always added. In some cases, you will need to add the always parameter to the Access-Control-Allow-Credentials header.
add_header 'Access-Control-Allow-Credentials' 'true' always;

You need to use the more_set_headers module.
with -s you can scpecify more status code
more_set_headers -s '404,400,403' 'Access-Control-Allow-Origin: http://domain.com';
However if you don't have installed this module in nginx you need to recompile it.
to compile it :
wget http://nginx.org/download/nginx-1.7.8.tar.gz
git clone https://github.com/openresty/headers-more-nginx-module.git
tar -xzvf nginx-1.7.8.tar.gz
cd nginx-1.7.8
./configure --prefix=/opt/nginx --add-module=/path/to/headers-more-nginx-module
make
make install

Related

nginx map of header from upstream goes to default

I want to have a conditional header based on a header I want to get from the upstream.
For some reason it always gets translated to default.
Configuration:
upstream service decides if a header called x-no-iframe-protection should exist.
main nginx:
map $http_x_no_iframe_protection $x_frame_options {
yes "";
default "SAMEORIGIN";
}
server {
...
add_header X-Frame-Options $x_frame_options;
...
}
No matter what I try - I get both headers:
$ curl -v myhost
...
< x-no-iframe-protection: yes
< x-frame-options: SAMEORIGIN
...
Just to clarify - I use the x-no-iframe-protection just as a trick to remove x-frame-options in specific cases. I'm OK with it staying (although it is not needed once parsed by nginx)
Anyways - how can I make it get caught in order to replace the header value?
An HTTP transaction contains request headers and response headers. From the context of your question you are setting the value of a response header based on the value of another response header (which was received from upstream).
Nginx stores request headers in variables with names beginning with $http_ and response headers in variables with names beginning with $sent_.
In addition, response headers received from upstream may also be stored in variables with names beginning with $upstream_http_.
In your configuration you use the variable $http_x_no_iframe_protection, whereas you should be using either $sent_x_no_iframe_protection or perhaps $upstream_http_x_no_iframe_protection.
All of the Nginx variables are documented here.
try using $upstream_x_no_iframe_protection to access upstream response header.

Upload file to Nginx with cURL

All,
I'm trying to upload a local file to my remote Nginx server via cURL. I have built Nginx from source with the upload module and the DAV module. At the bottom of the Nginx page, there is an example form to upload a file. I'm not sure how I would implement the form, and (several) Google searches have returned little helpful information about uploading directly to Nginx via cURL.
Current tech stack:
Nginx
Green Unicorn
Flask
Of all the different avenues I've tried, the following is the one that seems the most appropriate for the task.
curl -X POST -F "image=#example.gif" http://54.226.64.199/upload
However, the response is underwhelming.
I've tried --uploade-file as well, the response is a 405. From what I've read, upload only accepts a POST command, not PUT, hence why I get a 405.
I don't need a full solution (would be great!), only pointing in the right direction.
Any help is appreciated. Thanks
EDIT: sorry wanted to include part of my .conf
location /upload {
upload_store /tmp;
#upload_pass #none;
upload_store_access all:rw;
upload_cleanup 400 404 499 500-505;
}
You can do this by specifying filename into URL, without using any external module :
location ~ "/upload/([0-9a-zA-Z-.]*)$" {
alias /storage/www/upload/$1;
client_body_temp_path /tmp/upload_tmp;
dav_methods PUT DELETE MKCOL COPY MOVE;
create_full_put_path on;
dav_access group:rw all:r;
}
And use : curl -T example.gif http://54.226.64.199/upload/example.gif

Nginx auth_request handler accessing POST request body?

I'm using Nginx (version 1.9.9) as a reverse proxy to my backend server. It needs to perform authentication/authorization based on the contents of the POST requests. And I'm having trouble reading the POST request body in my auth_request handler. Here's what I got.
Nginx configuration (relevant part):
server {
location / {
auth_request /auth-proxy;
proxy_pass http://backend/;
}
location = /auth-proxy {
internal;
proxy_pass http://auth-server/;
proxy_pass_request_body on;
proxy_no_cache "1";
}
}
And in my auth-server code (Python 2.7), I try to read the request body like this:
class AuthHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def get_request_body(self):
content_len = int(self.headers.getheader('content-length', 0))
content = self.rfile.read(content_len)
return content
I printed out the content_len and it had the correct value. However, the self.rfile.read() will simply hang. And eventually it will time out and returns "[Errno 32] Broken pipe".
This is how I posted test data to the server:
$ curl --data '12345678' localhost:1234
The above command hangs as well and eventually times out and prints "Closing connection 0".
Any obvious mistakes in what I'm doing?
Thanks much!
The code of the nginx-auth-request-module is annotated at nginx.com. The module always replaces the POST body with an empty buffer.
In one of the tutorials, they explain the reason, stating:
As the request body is discarded for authentication subrequests, you will
need to set the proxy_pass_request_body directive to off and also set the
Content-Length header to a null string
The reason for this is that auth subrequests are sent at HTTP GET methods, not POST. Since GET has no body, the body is discarded. The only workaround with the existing module would be to pull the needed information from the request body and put it into an HTTP header that is passed to the auth service.

How can remove Nginx from http response header?

I want to remove Nginx from http response header. I can Hide my Nginx version but I want to hide Nginx too.
Thanks
Use the ngx_headers_more module - see http://wiki.nginx.org/NginxHttpHeadersMoreModule.
It allows you to configure any arbitrary headers you'd like - both request and response headers. Once you've installed it (and thus recompiled your version of Nginx), use the following configuration:
more_set_headers 'Server: my-server';
Alternatively, if you don't want a Server header at all, then clear it using:
more_clear_headers 'Server';

How do you change the server header returned by nginx?

There's an option to hide the version so it will display only nginx, but is there a way to hide that too so it will not show anything or change the header?
If you are using nginx to proxy a back-end application and want the back-end to advertise its own Server: header without nginx overwriting it, then you can go inside of your server {…} stanza and set:
proxy_pass_header Server;
That will convince nginx to leave that header alone and not rewrite the value set by the back-end.
The last update was a while ago, so here is what worked for me on Ubuntu:
sudo apt-get update
sudo apt-get install nginx-extras
Then add the following two lines to the http section of nginx.conf, which is usually located at /etc/nginx/nginx.conf:
sudo nano /etc/nginx/nginx.conf
server_tokens off; # removed pound sign
more_set_headers 'Server: Eff_You_Script_Kiddies!';
Also, don't forget to restart nginx with sudo service nginx restart.
Like Apache, this is a quick edit to the source and recompile. From Calomel.org:
The Server: string is the header which
is sent back to the client to tell
them what type of http server you are
running and possibly what version.
This string is used by places like
Alexia and Netcraft to collect
statistics about how many and of what
type of web server are live on the
Internet. To support the author and
statistics for Nginx we recommend
keeping this string as is. But, for
security you may not want people to
know what you are running and you can
change this in the source code. Edit
the source file
src/http/ngx_http_header_filter_module.c
at look at lines 48 and 49. You can
change the String to anything you
want.
## vi src/http/ngx_http_header_filter_module.c (lines 48 and 49)
static char ngx_http_server_string[] = "Server: MyDomain.com" CRLF;
static char ngx_http_server_full_string[] = "Server: MyDomain.com" CRLF;
March 2011 edit: Props to Flavius below for pointing out a new option, replacing Nginx's standard HttpHeadersModule with the forked HttpHeadersMoreModule. Recompiling the standard module is still the quick fix, and makes sense if you want to use the standard module and won't be changing the server string often. But if you want more than that, the HttpHeadersMoreModule is a strong project and lets you do all sorts of runtime black magic with your HTTP headers.
It’s very simple: Add these lines to server section:
server_tokens off;
more_set_headers 'Server: My Very Own Server';
Simple, edit /etc/nginx/nginx.conf and remove comment from
#server_tokens off;
Search for http section.
Install Nginx Extras
sudo apt-get update
sudo apt-get install nginx-extras
Server details can be removed from response by adding following two lines in the nginx.conf (under http section)
more_clear_headers Server;
server_tokens off;
There is a special module: http://wiki.nginx.org/NginxHttpHeadersMoreModule
This module allows you to add, set, or clear any output or input header that you specify.
This is an enhanced version of the standard headers module because it provides more utilities like resetting or clearing "builtin headers" like Content-Type, Content-Length, and Server.
It also allows you to specify an optional HTTP status code criteria using the -s option and an optional content type criteria using the -t option while modifying the output headers with the more_set_headers and more_clear_headers directives...
If you're okay with just changing the header to another string five letters or fewer, you can simply patch the binary.
sed -i 's/nginx\r/thing\r/' `which nginx`
Which, as a solution, has a few notable advantages. Namely, that you can allow your nginx versioning to be handled by the package manager (so, no compiling from source) even if nginx-extras isn't available for your distro, and you don't need to worry about any of the additional code of something like nginx-extras being vulnerable.
Of course, you'll also want to set the option server_tokens off, to hide the version number, or patch that format string as well.
I say "five letters or fewer" because of course you can always replace:
nginx\r\0
with
bob\r\0\r\0
leaving the last two bytes unchanged.
If you actually want more than five characters, you'll want to leave server_tokens on, and replace the (slightly longer) format string, although again there's an upper limit on that length imposed by the length of the format string - 1 (for the carriage return).
...If none of the above makes sense to you, or you've never patched a binary before, you may want to stay away from this approach, though.
According to nginx documentation it supports custom values or even the exclusion:
Syntax: server_tokens on | off | build | string;
but sadly only with a commercial subscription:
Additionally, as part of our commercial subscription, starting from
version 1.9.13 the signature on error pages and the “Server” response
header field value can be set explicitly using the string with
variables. An empty string disables the emission of the “Server”
field.
After I read Parthian Shot's answer, I dig into /usr/sbin/nginx binary file. Then I found out that the file contains these three lines.
Server: nginx/1.12.2
Server: nginx/1.12.2
Server: nginx
Basically first two of them are meant for server_tokens on; directive (Server version included).
Then I change the search criteria to match those lines within the binary file.
sed -i 's/Server: nginx/Server: thing/' `which nginx`
After I dig farther I found out that the error message produced by nginx is also included in this file.
<hr><center>nginx</center>
There are three of them, one without the version, two of them included the version. So I run the following command to replace nginx string within the error message.
sed -i 's/center>nginx/center>thing/' `which nginx`
The only way is to modify the file src/http/ngx_http_header_filter_module.c . I changed nginx on line 48 to a different string.
What you can do in the nginx config file is to set server_tokens to off. This will prevent nginx from printing the version number.
To check things out, try curl -I http://vurbu.com/ | grep Server
It should return
Server: Hai
I know the post is kinda old, but I have found a solution easy that works on Debian based distribution without compiling nginx from source.
First install nginx-extras package
sudo apt install nginx-extras
Then load the nginx http headers more module by editing nginx.conf and adding the following line inside the server block
load_module modules/ngx_http_headers_more_filter_module.so;
Once it's done you'll have access to both more_set_headers and more_clear_headers directives.
Expanding on Parthian Shot's answer, you can actually replace the whole header and not only the value as long as the total length is the same:
sed -i 's/Server: nginx/My-Header: hi/' `which nginx`
Nginx-extra package is deprecated now.
The following therefore did now work for me as i tried installing various packages
more_set_headers 'Server: My Very Own Server';
You can just do the following and no server or version information will be sent back
server_tokens '';
if you just want to remove the version number this works
server_tokens off;
Are you asking about the Server header value in the response? You can try changing that with an add_header directive, but I'm not sure if it'll work. http://wiki.codemongers.com/NginxHttpHeadersModule

Resources