I have a zuul routing app deployed on the cloud. Below in my application.yml
---
spring:
profiles: default
zuul:
routes:
cloud:
path: /cardsvcs/acs/**
sensitiveHeaders:
url: https://vst0.mapi.checkFin.com/
stripPrefix: false
ribbon:
eureka:
enabled: false
Routing works perfectly fine and I also get the response headers back from the back end service. The requestContext originResponseHeaders also have all the cookies as part of setCookie header. But these cookies are not visible on the Postman response after routing.
Do we need to gets the cookies from this header in the filter and map them again?
Please try the below.
zuul.sensitiveHeaders: Authorization
The sentive-headers that are configured in zuul are not passed to downstream servers. And below three headers are defaults.
zuul.sensitiveHeaders: Cookie,Set-Cookie,Authorization
To pass cookie related headers to your downstream server, you need to redefine above propeprties.
Please refer to the section 'Cookies and Sensitive Headers' in the the linked doc : http://cloud.spring.io/spring-cloud-static/Dalston.RELEASE/
Related
My stack is the following: NestJS backend (Express under the hood) deployed on Elastic Beanstalk, NextJS frontend deployed on AWS Amplify, CloudFront as CDN, and I can't get Set-Cookie header back to the frontend NextJS app, nor a cookie is being set.
FE and BE are on a different domains.
Locally everything works fine, when FE and BE apps are local, eg. I'm getting Set-Cookie and a cookie is stored in the browser. When FE is local and BE is deployed, it doesn't work as expected also when communicating between the two. CORS is being set up and there's no error there. Cookie options seems right too.
On the backend, CORS has been set with 3 options, out of the factory method, eg. app.enableCors({...}):
explicit origin (no wildcard) - works with allowed credentials turned on
credentials set to true - allow credentials header
allowed headers
So, CORS is working, no error there, just not returning Set-Cookie header when deployed.
For cookie, I'm using cookie-parser npm module, and having set up the following options for the cookie when returning the response for POST /auth/login request:
httpOnly: true - no script reading
maxAge (1 day into the future from request time)
sameSite: 'none' - cross-site enabled
secure: true - https (required for cross-site)
On the frontend, I'm using NextJS with axios npm module to fetch an API. Also, I'm having credentials set to true.
I tried to update CORS settings on load balancers, eg. proxy for the backend, and was doing a lot of research on Stack Overflow and other platforms, but couldn't find a solution. Most solutions mention that some options are missing for the backend, like CORS and a cookie settings, and credentials: true for the frontend. But as mentioned before, seems I got that covered. CloudFront settings didn't help either. CloudFront caching policy - didn't help. Something is missing or am doing it wrong.
Everything points that the AWS has to be set up properly(default/basic settings), but I don't know what excatly. Any help?
I followed the guide to set up an external global, app engine based, load balancer. I linked it to Google's CDN by ticking the little box in the LB configuration settings.
Now, when I load my domain name, it says CANNOT GET /. The request returns a 404, along with some C S P: The page’s settings blocked the loading of a resource at inline (“default-src”). error messages.
It was working well before adding the CDN. So, I'm assuming my app server configuration is fine.
In the Load Balancer details, there is a little chart under the Monitoring section, with how traffic flows.
It shows traffic coming from the 3 global regions, going to the frontend of the LB, then to / (unknown) and / (unmatched) as URL Rule, then to the backend service I defined, and finally to a backend instance labelled NO_BACKEND_SELECTED.
I'm guessing the issue comes either from the URL Rule or Backend Instance, but there is little in the doc. to troubleshoot.
I followed the doc. to setup the LB. Settings are pretty simple using App Engine, so there is little room for wrong doing. But I may have missed something still.
In the 'create serverless NEG', I did select App Engine, and default as the service name (although i'm not sure what default actually means).
Any idea what's missing ?
EDIT :
So, in the load balancing menu, I go to the 'Backends' section at the top, and select my backend. Here I have the list of 'General properties' of my backend. Except, under 'Backends', it says the following : Backends contain instance groups of VMs or network endpoint groups. This backend service has no backends yet edit
From there, I can click the edit link, which redirects me to the 'Backend service edit' menu. I DO have a backend selected in there. I did create a serverless NEG using App Engine.
So, what's missing ? Is there anything wrong with Google's serverless backend ?
I wanna help you with the issue that you are facing.
If the responses from your external backend are not cached by Cloud CDN
Ensure that:
-You have enabled Cloud CDN on the backend service containing the NEG that points to your external backend by setting enableCDN to true. (DONE as per your description).
-Responses served by your external backend meet Cloud CDN caching requirements. For example, you are sending Cache-Control: public, max-age=3600 response headers from the origin.
The current implementation of Cloud CDN stores responses in cache if all of the following are true.
Attribute:
Served by
Requirement:
Backend service, backend bucket, or an external backend with Cloud CDN enabled
Attribute:
In response to
Requirement:
GET request
Attribute:
Status code
Requirement:
200, 203, 204, 206, 300, 301, 302, 307, 308, 404, 405, 410, 421, 451, or 501.
Attribute:
Freshness
Requirement:
The response has a Cache-Control header with a max-age or s-maxage directive, or an Expires header with a timestamp in the future.
For cacheable responses without an age (for example, with no-cache), the public directive must be explicitly provided.
With the CACHE_ALL_STATIC cache mode, if no freshness directives are present, a successful response with static content type is still eligible for caching.
With the FORCE_CACHE_ALL cache mode, any successful response is eligible for caching.
If negative caching is enabled and the status code matches one for which negative caching specifies a TTL, the response is eligible for caching, even without explicit freshness directives.
Attribute:
Content
Requirement:
Contains a valid Content-Length, Content-Range, or Transfer-Encoding: chunked header.
For example, a Content-Length header that correctly matches the size of the response.
Attribute:
Size
Requirement:
Less than or equal to the maximum size.
For responses with sizes between 10 MB and 5 TB, see the additional cacheability constraints described in byte range requests.
Please validate the URL Mapping too:
This is an example as reference adapt this according your project.
Create a YAML file /tmp/http-lb.yaml, making sure to substitute PROJECT_ID with your project ID.
When a user requests path /*, the path gets rewritten in the backend to the actual location of the content, which is /love-to-fetch/*.
defaultService: https://www.googleapis.com/compute/v1/projects/PROJECT_ID/global/backendBuckets/cats
hostRules:
- hosts:
- '*'
pathMatcher: path-matcher-1
name: http-lb
pathMatchers:
- defaultService: https://www.googleapis.com/compute/v1/projects/PROJECT_ID/global/backendBuckets/cats
name: path-matcher-1
pathRules:
- paths:
- /*
routeAction:
urlRewrite:
pathPrefixRewrite: /love-to-fetch/
service: https://www.googleapis.com/compute/v1/projects/PROJECT_ID/global/backendBuckets/dogs
tests:
- description: Test routing to backend bucket, dogs
host: example.com
path: /love-to-fetch/test
service: https://www.googleapis.com/compute/v1/projects/PROJECT_ID/global/backendBuckets/dogs
Validate the URL map.
gcloud compute url-maps validate --source /tmp/http-lb.yaml
If the tests pass and the command outputs a success message, save the changes to the URL map.
Update the URL map.
gcloud compute url-maps import http-lb \
--source /tmp/http-lb.yaml \
--global
Using URL maps
I have a backend app in django python and it is being served on http://localhost:8000.
I have a angular frontend which is being served on http://localhost:4200.
I have disabled CORS on django.
On hitting the login api on http://localhost:8000/auth/login/, I am getting a valid response
along with the Set-Cookie header.
Here is my angular code to print the cookies:
this.http.post<any>('http://localhost:8000/auth/login/', this.LoginForm, { observe: 'response' }).subscribe(response => {
console.log("response is ", response);
var cookies = this.cookieService.getAll();//('cookies');
console.log("cookies is :", cookies);
It prints an empty object on console.
How do I make this work? I want to use cookies for authentication.
You are trying to set cross domain cookies, which will not work straight away. There are a few steps to follow to be able to do that.
Set withCredentials: true when making the authentication request from angular
this.http.post<any>('http://localhost:8000/auth/login/', this.LoginForm, { observe: 'response', withCredentials: true })
Configure your server to return the following CORS headers: Access-Control-Allow-Credentials: true and Access-Control-Allow-Origin: http://localhost:4200
Note
One of the cookies that you are setting is HttpOnly. As such, you cannot access it from Javascript (see documentation).
You may not need to access the cookies with JS anyway. If you just want to send the cookies in the next API requests, just pass withCredentials: true to HttpClient other api calls
this.http.get('http://localhost:8000/path/to/get/resource',
{ withCredentials: true }).subscribe(response => {
Set-Cookies:
In the example in the Question, both client and server are in the same domain, localhost.
On deployment, this may not be the case.
Let us assume the domains as below,
Client : client1.client.com
Server: server1.server.com
A http request from the Angular web app in client1.client.com to https://server1.server.com/api/v1/getSomething has Set-Cookie: JSESSIONID=xyz in the response header.
The cookie will be set on server1.server.com and NOT on client1.client.com.
You can enter server1.server.com in the URL bar and see the cookie being set.
withCredentials:
There is no need for the angular app to read the cookie and send it in the following requests. withCredentials property of http request can be used for this.
Refer: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials
Example:
public getSomething(): Observable<object> {
const httpOptions = {
withCredentials: true
};
return this.http.get(`${this.serverUrl}/getSomething`, httpOptions);
}
Refer: https://angular.io/api/common/http/HttpRequest
withCredentials will set the cookies from the server's domain in the requests to the server.
As mentioned before Set-Cookie: JSESSIONID=xyz in the response from server1.server.com will be set in server1.server.com. The Angular app in client1.client.com need not read it. withCredentials will take care of it.
cross domain issues:
When the server and client are in different domains, using withCredentials may not work in all browsers, as they are considered as third party cookies.
In my recent testing on May 2020, I found that withCredentials is not working in certain browsers when the client and server are in different domains.
In Safari, the issue occurs when "Prevent cross-site tracking" is enabled (by default). The issue is prevented by disabling the same. https://support.apple.com/en-in/guide/safari/sfri40732/mac
In Android apps, the issue can be avoided by using Chrome Custom Tabs instead of Android WebView. https://github.com/NewtonJoshua/custom-tabs-client , https://developer.chrome.com/multidevice/android/customtabs
Same domain:
Looks like mainstream browsers are moving to block third-party cookies.
Safari - Full Third-Party Cookie Blocking and More
Chrome (by 2022) - Building a more private web: A path towards making third party cookies obsolete
The solution is to have both the client and server in the same domain.
Client: client1.myapp.com
Server: server1.myapp.com
And in the Set-Cookie response include the root domain too.
Example: "JSESSIONID=xyz; Domain=.myapp.com; Path=/"
This will make sure the cookies are set in all cases.
I try to block the possibility to send a post request to my app via postman or insomnia. I want to limit the source of a request to one domain www.sample.com. I did add this domain to the ALLOWED_HOSTS and CORS_ORIGIN_WHITELIST, and nothing more and still I can send a request and save the data in my django app.
How can I limit the origin of a request to the one domain and block all others or return "Unauth msg"?
Stack: DJANGO REST Framework
I am able to add a check:
if not request.headers.__contains__("Origin") or request.headers["Origin"] not in HOSTS:
But I can fill the free field with key Origin and domain as a value in the postman app
You cannot prevent a HTTP client from setting a header. If your API is available on Internet it is possible to send you any header. CORS (Cross Origin Resource Sharing) rules are only applied in Web browsers.
I was hoping to get some recommendations on how to approach redirecting users from HTTP to HTTPS using an ember initializer with ember-simple-auth.
`import ENV from 'cio/config/environment'`
SSLInitializer =
name: 'ssl'
before: 'simple-auth-cookie-store'
initialize: (container, application) ->
application.deferReadiness()
# Redirect if hitting HTTP and SSL is enabled
if ENV.SSL and window.location.protocol is "http:"
window.location.href = "https:" + window.location.href.substring(window.location.protocol.length)
return false
application.advanceReadiness()
`export default SSLInitializer`
But it seems that the cookie gets invalidated even when the if statement evaluates to true. I've tried several things, including:
before: 'simple-auth'
before: 'store'
application.destroy() within the if statement, before the window.location.href is set
From what I can tell, after debugging. The app does redirect to HTTPS, but then the cookieName is not found in document.cookie. (https://github.com/simplabs/ember-simple-auth/blob/master/packages/ember-simple-auth-cookie-store/lib/simple-auth-cookie-store/stores/cookie.js#L154)
Before this method worked because we had simple snippet in the index.html, but w/ CSP we'd like to keep it in an initializer. Any recommendations?
Thanks!
You really should be forcing a redirect from HTTP to HTTPS from the server as doing it from the client does not add any real security.
Think about it, the user has downloaded the application to their browser from an insecure endpoint and from then on nothing can be trusted. Even a server based redirect is problematic since it relies on the redirect advice from an untrusted endpoint. Users should really be accessing things from an initial trusted starting point otherwise all bets are off. This is known as the secure referral problem and will likely never be solved because of the business model behind SSL certificates.
You also shouldn't really trust cookies from the untrusted HTTP domain in the trusted HTTPS domain unless you have a way to authenticate those cookies on the client. Sharing of cookies between HTTP/HTTPS is covered in RFC 2109 (Section 4.2.2 Set-Cookie Syntax).
This means:
A cookie set with "Secure" will be available only on HTTPS
A cookie set without "Secure" will be available on either HTTP or HTTPS.