Set mod_security to detectionOnly for a specific page? - apache

If mod_security is set to ON for the whole website, is there a way I can set specific pages to detection_only?
Use case is that the application is used to configure websites, and use of CSS or js is very common, but very likely to make modsecurity throw an XSS rule exception. I'd like to detect those exceptions but not block them, on those pages only. However on all other pages I want rule exceptions to block.
More gritty detail: The application is actually an IIS application running on another Windows server, while mod_security is running in Apache on a linux server. haproxy directs incoming requests to apache, and apache takes the request through modsecurity; if it passes, it reverse-proxies it back to haproxy, which then passes it to IIS.
== incoming request ==> haproxy ==> apache
v
mod_security
v
IIS machine <== haproxy <== mod_proxy
(yes, there's a good reason for using haproxy. We have hundreds of https certificates, and we can point haproxy at a folder full of them and it will pick the right one, based on the SNI https request. Haven't found anything else that can do that yet.)
So there's no directory on the apache side where a .htaccess file would make sense, at least to my tiny mind.
Paths to be treated as DetectionOnly would match the host admin.mysite.com and the path ^/site/[a-zA-Z0-9-]+/Settings$

Something like this should work (untested):
SecRule REQUEST_HEADERS:Host "#streq admin.mysite.com" "phase:1,id:1234,chain"
SecRule REQUEST_URI "^/site/[a-zA-Z0-9-]+/Settings$" "ctl:ruleEngine=DetectionOnly"
Just add that rule before any of the others and make sure the id is unique (I've used 1234 as an example).
The rule engine will be reset for the next request as ctl changes are for this request only.

Related

CloudFlare workers fetch HTTPS works on workers.dev subdomain but not on own subdomain getting 525 error

I have a simple worker that just does a fetch against an HTTPS endpoint somewhere else.
The code is literally just:
return await fetch('https://something.com/someResource')
When I test locally (wrangler dev) and even publish to a workers subdomain this works fine. When I curl https://foo.bar.workers.dev/myEndpoint I get the same response as https://something.com/someResource.
However I want to run this from my own domain (managed through cloudflare) so the worker also has a route of foo.mydomain.com/* and a AAAA record to 100:: for foo as per CloudFlare docs. The DNS works fine the URL is reachable, but when I try to hit https://foo.mydomain.com/myEndpoint CloudFlare's worker logs show that the fetch behind the scenes fails with a 525 error (SSL Handshake fail).
Things I've tried based on some CloudFlare forum posts:
Add a page rule foo.mydomain.com/* -> SSL Mode: full since my overall SSL settings are set to flexible.
Set the host header in the fetch to the origin domain ( fetch(url, {headers: {'Host': 'something.com'}})
FYI, I don't control the origin server as it's an external API I work with.
How come the same request works from local and *.workers.dev but not my own domain?
Your page rule is not taking effect. The page rule is for foo.mydomain.com/*, but it has to match the subrequest URL, which in this case is https://something.com/someResource, which doesn't match. It doesn't matter that the original worker request matched -- what matters, in this case, is whether the subrequest URL matched.
Unfortunately, you cannot create a page rule that matches a domain other than your own.
Instead, what you'll need to do is reverse things. Set your SSL mode to "full" by default, but then use page rules to set it to "flexible" for your own domain.
(Note: The "SSL Handshake fail" error itself is actually a known bug in Workers, that happens when you try to talk to a host outside your zone using HTTPS but you have "flexbile" SSL set. We do not use flexible SSL when talking to domains other than your own, but there's a bug that causes the request to fail instead of just using full SSL as it should.)

Apache 2.4 rewriting directory URLs without trailing slash to https://default_site/dir/ instead of preserving domain

This is a relatively recent behavioral change and appears to be related only to requests which include a "Upgrade-Insecure-Requests: 1" request header.
Apache has started rewriting such requests for sites which are HTTP-only to an HTTPS URL using the default site name instead of just adding the / at the end of the requested URL.
Example: URL submitted in browser: http://www.example.com/blah
Intended redirect: 301 to http://www.example.com/blah/
Instead redirects: 301 to https://default.site.configured/blah/
This happens whether it's a named virtual on the same address as the default server or a virtual using a separate address with separate Listen directives.
I understand all the arguments in favor of the idea that everything should always be encrypted and I don't want to get into a debate about that. This site doesn't consider the tradeoffs desirable at this time.
The default site does have SSL and is configured to redirect HTTP->HTTPS, but the www.foo.com site is not configured that way and does not wish to implement SSL at this time.
Is there any way to get Apache 2.4 to disregard that "Upgrade" header and simply rewrite the URL as desired rather than altering the domain name?
After banging on this some more, I finally found the source of my woes.
This happens when you have IP based virtual hosts and did not configure a name for them using the "ServerName" directive.
tl;dr: If you are having this problem, try adding a "ServerName www.example.com" directive within the VirtualHost definition for the site and that should resolve it.
Details:
It does not happen until you encounter a URL that requires a rewrite other than adding a trailing /. (i.e. if you get a request that doesn't contain the "Upgrade-Insecure-Requests: 1" header, it only gets the trailing / added, but if you get one with that header, it also tries to rewrite the protocol to https which triggers the full URL rewrite).
In my case, the default host name had an SSL configuration, so it didn't fall back to HTTP after the rewrite or reject the rewrite as invalid.
YMMV, I did not continue to do an exhaustive test of all permutations once I found the solution.

Why Firefox and Chrome insist on using HTTPS for a manually typed non-SSL website

I would appreciate some help to understand what is going on: both Firefox and Chrome are failing to load my non-SSL website, say subdomain.example.com, with the following SSL errors (both on ubuntu 14.04 i386):
FF30: ssl_error_rx_record_too_long
Chrome 35: ERR_SSL_PROTOCOL_ERROR
This started to occur after I set (and follow) a redirect (302) to SSL on the parent domain, say http://example.com to https://example.com. It gets back to normal after a full cache clean on the browser. But as soon as I access the parent domain I get the problem on the subdomain.
I have never entered the subdomain URL with the "https://" scheme prefix. I don't usually type any prefix and it is happening even if I explicitly prefix with "http://". And it is not only on the address bar, the same happens for links.
I am very confident that there is nothing wrong with the non-SSL site on the subdomain.
I thought about filling a bug report but it is unlikely this is a bug in both browsers and more likely I am missing something.
It there any rule that if a website on a given domain supports SSL (or redirects http to https), then sites on subdomains are assumed to do as well?
I later found the cause of the SSL errors. But the problem still persists (now the message is connection refused):
Apache web server was configured to listen on both ports 80 and 443, but with no "SSLEngine on" clause. This effectively makes it serve plain HTTP on port 443.
It is worth to mention that this Apache configuration mistake is not that hard to fall into. Actually, in the default Ubuntu configuration (possibly the same for Debian), it is just a matter of enabling/loading the SSL module (and not providing a site configuration that uses SSL).
I have just found the cause. The ssl site on the parent domain is including the following STS response header:
Strict-Transport-Security: max-age=31536000 ; includeSubDomains
That triggers the browser behavior by spec.

How to get tomcat to send redirects as https urls when apache handles ssl

I'm a bit out of my depth here and nothing I have found quite addresses my problem. Si any and all suggestions are most welcome.
I've got tomcat6 running on CentOS 6.5 hidden behind an apache server (v2.2.15) and I am using Apache's mod_proxy to expose the tomcat webapps, which are running on port 8080. The tomcat hosts one production application and several development applications. On the apache side, both a Drupal site and the aforementioned tomcat production application are on the same domain and, thanks to rewrite rules, all requests to this domain are changed to https. The development sites are reached via subdomains and do not get re-written as https requests.
For the most part, this arrangement works fine. But parts of the tomcat apps are AJAX (calling a Java Struts 1.2 backend). Most of those requests are handled OK. But a few AJAX requests result in redirects (i.e., forward.setRedirect(true)) and that redirect is http (I guess because the container itself is not secure). As a result, I run into cross site scripting issues. I imagine I can use CORS headers to avoid the problem. But that seems like a hack. Is there a relatively painless way I can use to have tomcat send redirects back as https without making tomcat handle ssl directly?
Cris
You could configure the RemoteIpValve in Tomcat:
Another feature of this valve is to replace the apparent scheme
(http/https) and server port with the scheme presented by a proxy or a
load balancer via a request header (e.g. "X-Forwarded-Proto").
To configure Apache to forward the original protocol in the X-Forwarded-Proto header, add a RequestHeader directive in your Apache config, e.g.:
<VirtualHost *:443>
RequestHeader set X-Forwarded-Proto "https"
...
Note that in Tomcat 7, there is also a RemoteIpFilter.
You don't need to do anything special. It already works. Make sure you set the "redirectPort" in server.xml to Apache's HTTPS port, usually 443, and add the following to your <security-constraint> sections for resources you want secured by HTTPS:
<user-data-constraint>
<description>HTTPS</description>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</‌​user-data-constraint>
Late to the game here but others may find this-- we had a similar setup and issue where everything worked fine until the application started using ajax posts which did redirects for the response. The fix was to use mod_header in apache to rewrite redirects using "Header edit Location"
http://httpd.apache.org/docs/current/mod/mod_headers.html
Header edit Location ^http://www.example.com/ https://www.example.com/
This went unnoticed prior to the ajax redirects because the browser has no problem doing page level redirects to http (which apache would then redirect back to https). But the ajax cross-site prevention halts at the initial http missing out on that would then be redirected to https by a subsequent request.

What is yourinfo.allrequestsallowed.net?

In my apache instillation, I keep seeing the following line in my access logs:
"POST http://yourinfo.allrequestsallowed.net/ HTTP/1.1" 200
It's really freaking me out because this site is not being hosted on my server (I checked the IP just to be 100% sure). I added a "Deny all" line since the site is still in development, and now the HTTP 200 response changed to 403, like the domain is being hosted on my server.
I'm incredibly confused and scared. Does anybody know what's going on? Can I Deny all to this domain that's apparently pointing to my server?
You may want to check to make sure you don't have ProxyRequests On set anywhere where it's not supposed to. Typically a request like that is for a forward proxy and the troubling bit is that you returned a 200 response which could indicate that the request was successfully proxied.
Take a look at this wiki page about Proxy abuse.
My server is properly configured not to proxy, so why is Apache returning a 200 (Success) status code?
That status code indicates that Apache successfully sent a response to the client, but not necessarily that the response was retrieved from the foreign website.
RFC2616 section 5.1.2 mandates that Apache must accept requests with absolute URLs in the request-URI, even for non-proxy requests. This means that even when proxying is turned off, Apache will accept requests that look like proxy requests. But instead of retrieving the content from the foreign site, Apache will serve the content at the corresponding location on your website. Since the hostname probably doesn't match a name for your site, Apache will look for the content on your default host.
But it's probably worthwhile to check that you aren't proxying. Otherwise, it's not really that big of a deal.
After Jon Lin pointed me in the right direction, I figured it out.
After disabling mod_proxy and enabling mod_security, I added the following to my virtual host configuration:
SecRuleEngine On
SecRule REQUEST_LINE "://" drop,phase:1
And then restarted apache. It quits the connection and returns any amount of data, which uses less resources and bandwidth during Brute Force and DDOS attacks.
Also, it shows as an HTTP 404 Response in the access logs.
EDIT: I updated the rule to drop all types or proxies (https,https,ftp). I don't know how many protocols can be used this way, but I'd rather be safe than sorry.