nginx wordpress xmlrpc protect from brutal attack - wordpress

I wish my xmlrpc.php only accessible by wordpress-jetpack and thrown 404 to anyone else
I tried
location ~ /xmlrpc.php {
if ($http_user_agent !~* ".*jetpack.*") {
return 403;
}
}
I still get error when try connect my site from wordpress.com
2017/04/16 09:28:39 [error] 24200#24200: *1453 access forbidden by rule, client: 162.158.69.63, server: example.com, request: "POST /xmlrpc.php?for=jetpack&token=4xm%28
how do I create a redirect rules if $request_uri not contain "jetpack" then return 404 ?

I guess you just make a small, hm.. let's call it typo. You are using $http_user_agent in an attempt to check User Agent, but what you need to use is $request_uri or (as you specially ask for ) $query_string.
So Conf for xmlrpc location will work perfectly fine here.
location ~ /xmlrpc.php {
if ( $query_string !~* ".*jetpack.*" ) {
return 404;
}
}

Related

How to get nginx to do a redirect to url-encoded query parameter

I have a requirement to do a proxy call to url delivered via a query parameter as per example:
My nginx proxy is deployed at: https://myproxy.net
if the redirect parameter is not url encoded I can do the call with this block:
location /basepath {
if ( $arg_redirect = '') {
return 400 "Missing redirect directive in request";
}
proxy_pass $arg_redirect;
proxy_intercept_errors on;
error_page 301 302 307 = #handle_redirects;
}
the error intercepts and #handle_redirects then take care of othe 30X codes that might pop up at new destination.
This works for a request:
GET: https://myproxy.net/basepath?redirect=https://destination.com/somepath/uuid
What do I need to do to make it work for:
GET: https://myproxy.net/basepath?redirect=https%3A%2F%2Fdestination.com%2Fsomepath%2Fuuid
Additionally as part of spec it has to be pure nginx, not additional modules, lua etc.
Thanks!
Actually, proxy_pass does normalisation by default, but it only affects $uri part. Thus you only need to decode the beginning of the passed string to get it working:
location / {
if ( $arg_redirect = '') {
return 400 "Missing redirect directive in request";
}
if ( $arg_redirect ~ (.+)%3A%2F%2F(.+) ){ # fix :// between scheme and destination
set $arg_redirect $1://$2;
}
if ( $arg_redirect ~ (.+?)%3A(.*) ){ # fix : between destination and port
set $arg_redirect $1:$2;
}
if ( $arg_redirect ~ (.+?)%2F(.*) ){ # fix / after port, the rest will be decoded by proxy_pass
set $arg_redirect $1/$2;
}
proxy_pass $arg_redirect;
}
With the above I managed to access http://localhost/?redirect=http%3A%2F%2F127.0.0.1%3A81%2Fsfoo%20something%2Fs
The solution seems dirty and the only alternative using default modules is map (even less cleaner in my opinion). I'd rather split redirect argument into pieces: scheme (http or https), destination, port, and uri. With that you would be able to construct full address without rewriting:
proxy_pass $arg_scheme://$arg_dest:$arg_port/$arg_uri
Ok, there is very weird and curious solution
server {
listen 80;
resolver x.x.x.x;
location /basepath {
if ($arg_redirect = '') {
return 400 "Missing redirect directive in request";
}
proxy_pass http://127.0.0.1:80/basepath/$arg_redirect;
}
location ~ ^/basepath/(?<proto>\w+):/(?<redir>.+)$ {
proxy_pass $proto://$redir;
}
}
Nginx does not encode path with variables in proxy_pass and send it as is. So, I make $arg_* part of proxy_pass uri, send request to self and nginx will receive new request which will be decoded.
But because Nginx will clean path and replace // to / I split protocol part in regexp.
And ... I would never recommend using this solution, but it works :)
try like this and let me know if it works
location /basepath {
if ( $arg_redirect = '') {
return 400 "Missing redirect directive in request";
}
set_unescape_uri $decodedredirect $arg_redirect;
proxy_pass $decodedredirect;
proxy_intercept_errors on;
error_page 301 302 307 = #handle_redirects;
}

Different files by useragent in NGINX

How can I correctly write the configuration of the nginx server?
...
if the client has useragent (A) and it refers to http://somehost.domain/somefile.someextension
nginx responding a file from the root /file.zip
if the client has useragent (B) and it refers to http://somehost.domain/somefile.someextension
nginx responding a file from the root /file2.zip
if the client has useragent (C) and it refers to http://somehost.domain/somefile.someextension
nginx responding 403 error
...
I did this code:
map $http_user_agent $browser {
"~*Firefox" "/var/www/test1";
"~*Wget" "/var/www/test2";
"~*SomeUserAgent" "/var/www/test3";
}
server {
...
root $browser
But how do I get the condition to pass to any address http://somehost.domain/somefile.someextension?
You can use map, location and alias directives to map a specific URI to multiple files based on the value of a header.
For example (where all of the files are in the same directory):
map $http_user_agent $browser {
default "nonexistent";
"~*Firefox" "file.zip";
"~*Wget" "file1.zip";
}
server {
...
location = /somefile.someextension {
alias /path/to/directory/$browser;
if (!-f $request_filename) {
return 403;
}
}
}
The if block is only required to change the 404 response to a 403 response.
See this document for more.

Wordpress NGINX redirect everything to new domain EXCEPT

I have an unusual setup in that I have an angularJS application running on http://example.com which pulls data via the wordpress api located at http://api.example.com.
http://api.example.com needs to have the /wp-login, /wp-admin, /wp-content, and /wp-includes urls to work as if it is still a regular wordpress site.
However all other url's like http://api.example.com/category/excategory or http://api.example.com/this-is-a-post-title need to redirect 301 to the http://example.com domain.
example:
http://api.example.com/category/excategory
redirects to
http://example.com/category/excategory
but
http://api.example.com/wp-admin (and anything after it)
does not.
I've tried all kinds of crazy things, but my location blocks seem to either conflict, or I get weird url's that go to nowhere.
Here's a try that failed:
location ~ /wp-(?:admin|login|includes|content) {
index index.php;
try_files $uri $uri/ /index.php?$args;
}
location / {
return 301 $scheme//example.com$request_uri
}
Put this code in your WP Theme Functions.php file. It should redirect all urls except the one who contain wp-admin:
add_action('init','_redirect_api_url');
function _redirect_api_url(){
$redirect = TRUE;
$pathNotToRedirect = array('wp-admin','wp-content', 'wp-login','wp-includes');
$path = "http://example.com".$_SERVER['REQUEST_URI'];
foreach($pathNotToRedirect as $val){
if(strpos($path, $val)){
$redirect = FALSE;
break;
}
}
if($redirect == TRUE) {
header("Location: ".$path);
}
}

nginx - valid_referes dont work

I have the local server running on 3000 port and it sends some POST request to nginx server. Nginx should check referer, if it is not coming from 127.0.0.1:3000 (with all subdomains) then return 403 Restricted,otherwise if it is valid redirect to 9200/errors/browser endpoint.
Currently, it is always redirecting regardless if the referer is valid or not. I know that in nginx if is evil , so if-else approach doesnt work here.
server {
listen 127.0.0.1:9999;
server_name localhost;
location / {
valid_referers none blocked server_names ~someaddress;
if ($invalid_referer) {
return 403;
}
# redirect to this endpoint if referer is valid
return 307 http://localhost:9200/errors/browser;
}
}
I should add
if ($invalid_referer != "1") {
return 403;
}
as it is the empty string according to the documentation
$invalid_referer
Empty string, if the “Referer” request header field value is considered valid, otherwise “1”.

Redirecting all requests that aren't from my IP with nginx

I want all nginx requests that aren't made by my IP address to be redirected to /some-page. I'm currently using this nginx config:
if ($remote_addr != 127.0.0.1) {
rewrite ^ http://www.example.com/some-page;
}
This works for me as I'm not redirected, but anyone else is stuck in a redirect loop since the block doesn't check if the request is for /some-page.
How can I fix this? I'm not sure how to check the request path.
If this if is created inside the location / for example, create a separate location /some-page this way the if won't be executed when the URI is /some-page
EDIT: ok let me explain what i understood and you tell me if i'm right or wrong,
Good IP (yours): serve page as it is
Bad IP (not yours): redirect to /some-page
The problem is, when Bad IP is redirected to /some-page it still redirects to /some-page again because it's still a Bad IP, so it passes the if test
My solution: Remove the /some-page location from the / block:
location / {
# bla bla
if ($remote_addr != 127.0.0.1) {
rewrite ^ http://www.example.com/some-page;
}
# rest of bla bla
}
location /some-page {
try_files index.html index.php; # or whatever
}
When Bad IP is forwarded to /some-page it no longer will execute the if condition, so that will end the infinite redirection loop.
Second EDIT: You could set the permissions in nginx it self, let me demonstrate:
location / {
error_page 403 = #badip
allow 127.0.0.1;
deny all;
#rest of bla bla
}
location #badip {
return 301 $scheme://example.com/some-page;
}
I ended up solving the issue by doing another if check for the request path. I knew nginx doesn't support nested if statements so I searched and found this blog post which provides a workaround -- updating a variable with each statement you want to check and then matching it in a final statement. In my case, I did this, which works:
if ($remote_addr != 127.0.0.1) {
set $check O;
}
if ($request_uri != "/some-page") {
set $check "${check}K";
}
if ($check = OK) {
rewrite ^ http://www.example.com/some-page;
}

Resources