challenging direct traffic using AWS ACL - amazon-web-services

We used to use cloudflare where setting up a challenge for direct traffic is pretty straight forward but we have now moved entirely to AWS cloudfront and for the life of me cannot see a way of setting up a rule to challenge direct traffic with a captcha or challenge
I followed a blog post to setup a referrer channel, but 'Match type' and 'Value to match' do not have the terms required to filter direct traffic
eg match type doesn't have an 'exclude term'
and 'Value to match' cannot contain 'nothing'

Related

Equivalent alternative to Whitelisting Twilio requests in CloudFlare

My requirement:
Prevent non Twilio access to my ALB managed Application using CloudFlare.
My restrictions:
Due to the nature of Twilio's cloud design, it is not possible to whitelist access down to a set of IPs due to the wide pool of IPs a request could come from.
Possible solution:
Twilio suggest a couple of options under https://www.twilio.com/docs/usage/security but I don't know how to use any of these methods as a means to only allow twilio Traffic. But any designed validation must only be applied to the dns record of /api in the url to my site.
Further Info:
The underlying application is written in php.
I would prefer a CloudFlare solution over changing code in the application.
A possible approach could be:
Use Cloudflare Firewall Rules to check for the presence of X-Twilio-Signature on your api path (as a first, basic check), block requests that do not have it.
Use a Cloudflare Worker, configured on your API path. The worker code can read X-Twilio-Signature and the request data, and use the procedure described in the Twilio documentation to validate it. If it matches, forward the request to your load balancer. If it doesn't, return an error to the caller.
Also, make sure your origin server only accepts traffic from Cloudflare to prevent direct tampering.

How to reject requests to Google External HTTPS Load Balancer that do not have a host header?

I have a cloud run service behind an HTTPS external load balancer. I'm seeing a number of path scanning style requests (e.g. "/owa", "/admin") that are trying to find vulnerabilities. None of these are supplying a host header.
To reduce unnecessary startups of my cloud run container, and to minimise exposing information to random IP address scanners, I'm trying to find a way to reject requests to my load balancer that are missing a host header.
What I had hoped to do was to respond with a static 403 forbidden style response. However, from the documentation this isn't possible. The best I have come up with is specifying a "Default URL Redirect" in my url map to send all traffic to google.com that doesn't match any host rule in my url map. This works, but seems clunky and perhaps not appropriate.
Is it possible to send a static response - or is it only possible to redirect? Is there a better way to solve this?
The correct answer from a GCP product perspective:
Use a Cloud Armor rule to effect the desired behaviour
This allows you to control a range of aspects of the response.
Alternate options you could consider:
Create an empty bucket and have that as the default backend.
A barebones nginx service on cloud run as the default backend that returns your desired status code.

Block all except whitelisted IPs

I would like to block all access to our demo site for some time with the exception of a group of listed IPs & IP ranges. Could you advise on how to do this?
I am hosting on digital ocean and I have cloudflare activated.
Thanks for the help anyways
This should be straightforward to achieve:
Ensure that the DNS record for your demo site is proxied by Cloudflare. You can check this in the Cloudflare Dashboard for your domain, in the DNS tab.
Add a Firewall Rule that will block all the traffic for your demo site unless it is coming from a list of allowed IP addresses. For example, using an expression such as:
(not ip.src in {192.0.2.1 192.0.2.2 192.0.2.3} and http.host eq "demo.example.com")
You can also define an IP List and reference to it in your Firewall rule - this would make it easier to maintain the list over time in a single place.
You can then turn the rule ON and OFF when needed.

Restricting website access by country

I am hosting my website using AWS.
The website is on 2 ec2 instances, with a load balancer (ELB) balancing traffic between them.
Currently, I am using my DNS (Route 53) to restrict the access to the website by using Route 53's geolocation routing:
http://docs.aws.amazon.com/Route53/latest/DeveloperGuide/routing-policy.html#routing-policy-geo
(The geolocation restriction is just to limit the initial release of my website. It is not for security reasons. Meaning the restriction just needs to work for the general public)
This worries me a little because my load balancer is still exposed to access from everywhere. So I am concerned that my load balancer will get indexed by google or something and then people outside of my region will be able to access the site.
Are there any fixes for this? Am I restricting access by location the wrong way? Is there a way perhaps to specify in the ELB's security group that it only receive inbound traffic from my DNS (of course then I would also have to specify that inbound traffic from edge locations be allowed as well for my static content but this is not a problem)?
Note: There is an option when selecting inbound rules for a security group, under "type" to select "DNS(UDP)" or "DNS(TCP)". I tried adding two rules for both DNS types (and IP Address="anywhere") for my ELB but this did not limit access to the ELB to be solely through my DNS.
Thank you.
The simple solution, here, is found in CloudFront. Two solutions, actually:
CloudFront can use its GeoIP database to do the blocking for you...
When a user requests your content, CloudFront typically serves the requested content regardless of where the user is located. If you need to prevent users in specific countries from accessing your content, you can use the CloudFront geo restriction feature[...]
http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/georestrictions.html
You can configure CloudFront with which countries are allowed, or which are denied. You can also configure static pages, stored in S3, which are displayed to denied users. (You can also configure static custom error pages for other CloudFront errors that might occur, and store those pages in S3 as well, where CloudFront will fetch them if it ever needs them).
...or...
CloudFront can pass the location information back to your server using the CloudFront-Viewer-Country: header, and your application code, based on the contents accompanying that header, can do the blocking. The incoming request looks something like this (some headers munged or removed for clarity):
GET / HTTP/1.1
Host: example.com
X-Amz-Cf-Id: 3fkkTxKhNxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==
Via: 1.1 cb76b079000000000000000000000000.cloudfront.net (CloudFront)
CloudFront-Viewer-Country: US
CloudFront-Forwarded-Proto: https
Accept-Encoding: gzip
CloudFront caches the responses against the combination of the requested page and the viewer's country, and any other whitelisted headers, so it will correctly cache your denied responses as well as your allowed responses, independently.
Here's more about how you enable the CloudFront-Viewer-Country: header:
If you want CloudFront to cache different versions of your objects based on the country that the request came from, configure CloudFront to forward the CloudFront-Viewer-Country header to your origin. CloudFront automatically converts the IP address that the request came from into a two-letter country code.
http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/header-caching.html#header-caching-web-location
Or, of course, you can enable both features, letting CloudFront do the blocking, while still giving your app a heads-up on the country codes for the locations that were allowed through.
But how do you solve the issue with the fact that your load balancer is still open to the world?
CloudFront has recently solved this one, too, with Custom Origin Headers. These are secret custom headers sent to your origin server, by CloudFront, with each request.
You can identify the requests that are forwarded to your custom origin by CloudFront. This is useful if you want to know whether users are bypassing CloudFront[...]
http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/forward-custom-headers.html
So, let's say you added a custom header to CloudFront:
X-Yes-This-Request-Is-Legit: TE9MIHdoYXQgd2VyZSB5b3UgZXhwZWN0aW5nIHRvIHNlZT8=
What's all that line noise? Nothing, really, just a made up secret value that only your server and CloudFront know about. Configure your web server so that if this header and value are not present in the incoming request, then access is denied -- this is a request that didn't pass through CloudFront.
Don't use the above secret, of course... make up your own. It's entirely arbitrary.
Caveat applicable to any GeoIP-restricting strategy: it isn't perfect. CloudFront claims 99.8% accuracy.
The most reliable way to implement geographic IP restrictions, is to use a geographic location database or service API, and implement it at the application level.
For example, for a web site in practically any language, it is very simple to add test at the start of each page request, and compare the client IP against the geo ip database or service, and handle the response from there.
At the application level, it is easier to manage the countries you accept/deny, and log those events, as needed, than at the network level.
IP based geo location data is generally reliable, and there are many sources for this data. While you may trust AWS for many things, I do think that there are many reliable 3rd party sources for geo IP dat, that focus on this data.
freegeoip.net provides a public HTTP API to search the geolocation of IP addresses. You're allowed up to 10,000 queries per hour.
ip2location.com LITE is a free IP geolocation database for personal or commercial use.
If your application uses a database, these geo databases are quite easy to import and reference in your app.
I have a post explaining in detail how to whitelist / blacklist locations with Route53: https://www.devpanda.me/2017/10/07/DNS-Blacklist-of-locations-countries-using-AWS-Route53/.
In terms of your ELB being exposed to public that shouldn't be a problem since the Host header on any requests to the ELB over port 80 / 443 won't match your domain name, which means for most web servers a 404 will be returned or similar.
There is a way using AWS WAF
You can select - Resource type to associate with web ACL as ELB.
Select your ELB and create conditions like Geo Match, IP Address etcetera.
You can also update anytime if anything changes in future.
Thanks

link a Google Domain to Amazon ec2 server

I am using an Amazon EC2 instance to serve a node.js app. I recently purchased a domain name through Google Domains and I want to use that domain name to access my node.js app.
The Google Domains console allows you to forward your domain traffic to another website. I set it to forward traffic to the public IP address of my EC2 instance. I can access my app just fine now, but when I type www.myDomainName.com into a web browser, the URL bar immediately changes and displays the digits of my EC2 IP address.
I would like the URL bar to display the name of my domain instead.
Note:
I have read a few SO questions related to this and can't figure it out. Some of them are a bit over my head. Many of them say to use an Amazon Elastic IP, but I don't understand why this is necessary if the public IP of my EC2 instance seems to work just fine. If the solution here is to use Amazon Elastic IP, I would really appreciate an explanation as to why that is necessary,
It sounds like you are using Google Domains to redirect to another site once the request has hit the Google servers. This is fine and dandy if you have another domain you are wanting to redirect to.
If you want it to stay under your domain name, but point to another location you need to actually change the DNS entries for your domain.
Go to Google Domain services and change your master(*) (A) record, as well as your WWW (A) record, to point at your public IP address. That way when a DNS request is sent for your domain it will just ask Amazons' servers what to do instead of using a redirect from Google.
Exact Steps:
From the Google Domain Website, click the Middle Tab () to open DNS settings
Fill out the form near the bottom of the page titled, Custom Resource Record
Name: In this scenario we want to use "#" or "www"
# is the root record (or anything not specifically set)[all]
www is the record for when people type www.example.com
Type: There are two types; A refers to IPv4 address and AAAA refers to IPv6 address
You can set both of them separately, generally you want to use the A [IPv4]
TTL: Time to live, recommend leaving 1hr (this is an advanced attribute)
Data: The actual IP address you are wanting to point to (your website)
Example: 8.8.8.8 [Google Nameserver]
Now that are the blanks are filled out, press the "Add" button
Wait for the records to be updated publicly
This will take approx. 1hr (as long as you kept TTL at 1hr)
This step can take longer depends on Google's servers
Check your website www.example.com to confirm it has updated
Addendum to Zax's Answer
While Zax's answer is fully accurate, it looks like it wasn't sufficient to help out the OP, and maybe not for others, too.
When you go to Google Domains (at least as of March 2017), you'll see several different tabs. The middle tab, which looks like is the tab to configure the DNS. Chose that tab.
Near the bottom of the page on the DNS tab you'll see a section Custom resource records. Within that section, you can add more entries. An entry consists of:
Name: this is briefly described by Google, but in short, likely you'll either want to use # or www, where the former means "root level" and the latter means "www subdomain".
For instance, if you registered imsocool.com, then # points to imsocool.com whereas www points to www.imsocool.com.
Type: you'll probably either want A which is an IPv4 Address or you'll want AAAA, which is an IPv6 Address. (That's assuming you're trying to point to a website, not an e-mail server or whatever else.)
TTL: time-to-live, I don't think you'll need to worry about it much, so just use the 1h (one hour) default.
data: again, presuming you are pointing to a website, that will be the actual IP address. E.g., 54.49.66.128, or whatever your IPv4 (or v6) server address is.
Once you've filled in all the blanks, simply hit the blue "Add" button.
Wait a while for the DNS update to happen.
The most it should take is 1 hour, if that's what you had placed above. But it could potentially be much quicker.
Then check to see that all is working by visiting your site using the name, e.g., imsocool.com.
In your google domain admin dashboard, select the dns configuration of your domain name.
Go to Custom resource records and set a new record with the subdomain you require: for the site webapp.example.com use webapp and select Type A. Leave blank the ttl field and add you public IP from the amazon EC2 instance. Then just browse the site webapp.example.com and it will retrieve the site on your EC2 under the domain name.
If you need to redirect the www.example.com domain then just add a record with www, also selecting the type A and adding your public IP from your EC2 instance.