How to set a cookie with Gin JWT middleware - go

I believe I successfully implemented the JWT middleware for Gin Gonic by following the example in the readme.
It is my understanding that upon retrieving an access token, I should also retrieve a refresh token that is being stored in a http only cookie.
There is an option for this:
SendCookie: true,
SecureCookie: false, //non HTTPS dev environments
CookieHTTPOnly: true, // JS can't modify
So I was under the impression that after logging in (and thereby getting the access token), a cookie with the refresh token is stored simultaneously. It appears if this is not the case, because I can't see any cookie in the browser's dev tools. What am I missing here?

It was actually set, one can check when looking at the response in the network tab of the browser's developer tools.
I could, however, not see it in the cookies section (dev tools > application) because it had the wrong domain. Apparently there is a bug in the middleware that causes troubles when the domain is set to localhost with a specific port.

Related

Can we remove using cookie from laravel sanctrum?

Is there way to remove cookie based feature from laravel sanctum and only use Authorization Bearer token way.
As, by default it sets and check through cookie and this feature don't work when API is deployed with different server then front-end.
Yes, it is possible.
\Laravel\Sanctum\Guard goes through config sanctum.guard, default value is web, so you can set this config in your config/sanctum.php file to whatever suits your need.
Eventually, you can change your web middleware group, if your SPA is the only GUI client.
If any of mentioned options is viable or smart is another question, to which I'd reply: "nope, configure your app properly to send and accept security headers and/or cookies with cors settings fitting your needs."

CSRF token not sent from Angular to Spring

We are building a web application using Angular and Spring Boot. As one of our security measures, we use CSRF tokens. The issue is that, on our local machines, the token validation works, but on our staging server, the tokens aren't sent by the frontend. The problem has suddenly occurred; we didn't have this problem for the first few months of using the tokens. After a certain build, they started failing. Then after a while, they were working again, but now have ceased working once more.
So, it seems like there is an environment issue that we fail to see.
What we can see
Spring is creating the CSRF token and sending it on preflight (OPTIONS) requests. It encapsulates the token in the Set-Cookie header, which Angular reads using the CookieXSRFStrategy. Again, locally this works fine, but on our staging server this fails. The issue is that Angular doesn't set the cookie after receiving the token. We checked this by inspecting the cookies in the Google Dev Console.
The specific error given by Spring is:
Invalid CSRF Token was found on the request parameter '_csrf' or
header 'X-CSRF-TOKEN'
The issue this causes
We can't login, since Spring doesn't receive a CSRF token. Therefore we can't do anything with the application unless we turn off CSRF protection completely.
We have tried
Specifically whitelisting cookies for the application in Chrome.
Clearing cookies and cache.
Trying in different browsers, on different machines. This happens in Chrome, IE11 and Firefox. We haven't tried any other browsers.
Making sure the origin is allowed through CORS, which it is. We do this with the Access-Control-Allow-Origin header.
Exposing more headers, like Set-Cookie using the Access-Control-Expose-Headers header. This doesn't change anything.
Allowing more headers, using Access-Control-Allow-Headers. This doesn't change anything either.
Simulating the login process using cURL (with the Postman application). This works. So it's an issue of Angular not being able to process the token properly.
Reading the headers manually with JavaScript/TypeScript. This didn't seem to work since the header wasn't exposed.
After struggling with the issue, we decided to integrate Docker, in an effort to mirror our staging and local environments. This didn't resolve the issue.
Reverting back to a previous build didn't work either.
Important notes
Both locally and on the staging environment we use an SSL certificate. Locally, we use a self-signed certificate.
All of the application runs on a Wildfly server. Both the Angular and Spring code is built and distributed using WAR files, which Wildfly deploys.
We are using a corporate proxy. The staging server is hosted in-house, and is only accessible when you're on the corporate network.
Versions
Angular: 4.2.2
Spring Boot: 1.4.1
Wildfly: 10.1.0.Final
Our current workaround is that we have disabled CSRF protection completely, so as to be able to continue development while we are looking for a solution.
Does anyone have any idea what could be going wrong?
The exception Invalid CSRF Token was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN' occurs when an invalid CSRF token is passed. If Spring would receive no CSRF token at all, it would print a different message "Could not verify the provided CSRF token because your session was not found." That means frontend is sending old or invalid CSRF token.
Possibly your corporate network proxy applies some login mechanism and override your X-CSRF-TOKEN header.
According to Spring Security documentation, cookieHttpOnly=false is needed to allow AngularJS to read the XSRF-TOKEN cookie.

Spring Security : restrict other web application access

I am running spring web application in broswer. I logged in to my account and update some value using a url say localhost:80/update/name. On the controller side I check principal==null if not redirect to login page.
Now while login to this application. I open other web application page in the same browser and execute the same update url localhost:80/update/name through ajax call and it is updating the value. How can i avoid this security threat.
How can i make sure that Application1 update url will be executed by application1 request only? Application2 should not be allowed to execute app1's update request no matter whether it is in same browser ?
Why are you surprised ? You are logged, thus the browser has a valid session cookie. You ask the browser to send a request to the host (be it in first window or any other window, it is the same) : it sends the request with all relevant cookies, including session cookie and if appropriate any other security cookie. The server receives a request containing a valid session cookie for a valid logged user and even if it controls IP addressed coming from same address : all is valid and it proceeds with the request.
If you have a different browser on your client machine and if you open the connection from this unrelated browser, the server should reject your request, because the browser would not present a valid cookie.
You are describing a variant of cross-site request forgery, you should enable Spring Security CSRF protection. You can read about it in the reference manual.
Even if the two applications are on the same server, they will get different CSRF tokens, which will protect your case.
You described Cross-Site request forgery attack. Typically when POST method is used hidden token is added to prevent it. I assume You are using GET method - It is good practice to not change any state using GET method.

share authentication between domain and subdomain in symfony 2.1

In an application I implemented an javascript chat with long polling. Since there is just one Ajax Request per domain allowed I wanted to move the poll request to a subdomain.
So I have two domains:
dev.site.com
poll.dev.site.com
In my config.yml I entered the following:
framework:
session:
domain: .dev.site.com
cookie_domain: .dev.site.com
But Symfony does not keep me logged in if I try to poll on the sub-domain via Ajax.
Any idea on how to keep the session on the sub-domains?
I'm using the FOSUserBundle
First, the two applications need to share the fos_user table so they can reload the user when. As you have "one app and the two domains pointing to the same app." this should already be correct.
Next is to set the session cookie to be shared between the domain and the subdomain. The config in your question is correct. However for FOSUserBundle to be able to reload the user when you change from dev.site.com to poll.dev.site.com you need to share the session storage between the two domain.
The easiest way I can suggest is to store the session in a database. This is achieved by using the PdoSessionStorage available in Symfony. The official documentation covers how to setup the session storage to do that.
If all above is done correct you should not able to login to an secure area on dev.site.com, and then change the URL to an other secure area on poll.dev.site.com without any need provide login credentials again. Notice that the user credentials are only loaded in an secure area.
When it works to open poll.dev.site.com directly in the browser with any need to enter the credentials again. You need to do some additional work to get the Ajax request to work.
According to these two questions: Setting a cookie on a subdomain from an ajax request, multi-sub-domain cookies and ajax problems the problem is likely the http://en.wikipedia.org/wiki/Same_origin_policy.
The first suggests setting the following header fields on dev.site.com:
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: http://poll.dev.site.com
And then passing withCredentials on the ajax request.
$.ajax({
url: 'http://poll.dev.site.com/some/ajax/endpoint.json',
xhrFields: {
withCredentials: true
}
});
I've tested it using a dummy file that would just set the cookie and try and ajax request. I got it to worked if I had withCredentials on the ajax request, but I could not see any difference when I tried with/without the Access-Control-Allow-* headers.
The other answer suggested using document.domain but I dodn't test that.
I used using Opera's Dragonfly to inspect the network trafic if the Cookie header was sent to the server when I tested. You can use Firebug, Chrome or probably IE too.

REST authentication and exposing the API key

I've been reading up on REST and there are a lot of questions on SO about it, as well as on a lot of other sites and blogs. Though I've never seen this specific question asked...for some reason, I can't wrap my mind around this concept...
If I'm building a RESTful API, and I want to secure it, one of the methods I've seen is to use a security token. When I've used other APIs, there's been a token and a shared secret...makes sense. What I don't understand is, requests to a rest service operation are being made through javascript (XHR/Ajax), what is to prevent someone from sniffing that out with something simple like FireBug (or "view source" in the browser) and copying the API key, and then impersonating that person using the key and secret?
We're exposing an API that partners can only use on domains that they have registered with us. Its content is partly public (but preferably only to be shown on the domains we know), but is mostly private to our users. So:
To determine what is shown, our user must be logged in with us, but this is handled separately.
To determine where the data is shown, a public API key is used to limit access to domains we know, and above all to ensure the private user data is not vulnerable to CSRF.
This API key is indeed visible to anyone, we do not authenticate our partner in any other way, and we don't need REFERER. Still, it is secure:
When our get-csrf-token.js?apiKey=abc123 is requested:
Look up the key abc123 in the database and get a list of valid domains for that key.
Look for the CSRF validation cookie. If it does not exist, generate a secure random value and put it in a HTTP-only session cookie. If the cookie did exist, get the existing random value.
Create a CSRF token from the API key and the random value from the cookie, and sign it. (Rather than keeping a list of tokens on the server, we're signing the values. Both values will be readable in the signed token, that's fine.)
Set the response to not be cached, add the cookie, and return a script like:
var apiConfig = apiConfig || {};
if(document.domain === 'example.com'
|| document.domain === 'www.example.com') {
apiConfig.csrfToken = 'API key, random value, signature';
// Invoke a callback if the partner wants us to
if(typeof apiConfig.fnInit !== 'undefined') {
apiConfig.fnInit();
}
} else {
alert('This site is not authorised for this API key.');
}
Notes:
The above does not prevent a server side script from faking a request, but only ensures that the domain matches if requested by a browser.
The same origin policy for JavaScript ensures that a browser cannot use XHR (Ajax) to load and then inspect the JavaScript source. Instead, a regular browser can only load it using <script src="https://our-api.com/get-csrf-token.js?apiKey=abc123"> (or a dynamic equivalent), and will then run the code. Of course, your server should not support Cross-Origin Resource Sharing nor JSONP for the generated JavaScript.
A browser script can change the value of document.domain before loading the above script. But the same origin policy only allows for shortening the domain by removing prefixes, like rewriting subdomain.example.com to just example.com, or myblog.wordpress.com to wordpress.com, or in some browsers even bbc.co.uk to co.uk.
If the JavaScript file is fetched using some server side script then the server will also get the cookie. However, a third party server cannot make a user’s browser associate that cookie to our domain. Hence, a CSRF token and validation cookie that have been fetched using a server side script, can only be used by subsequent server side calls, not in a browser. However, such server side calls will never include the user cookie, and hence can only fetch public data. This is the same data a server side script could scrape from the partner's website directly.
When a user logs in, set some user cookie in whatever way you like. (The user might already have logged in before the JavaScript was requested.)
All subsequent API requests to the server (including GET and JSONP requests) must include the CSRF token, the CSRF validation cookie, and (if logged on) the user cookie. The server can now determine if the request is to be trusted:
The presence of a valid CSRF token ensures the JavaScript was loaded from the expected domain, if loaded by a browser.
The presence of the CSRF token without the validation cookie indicates forgery.
The presence of both the CSRF token and the CSRF validation cookie does not ensure anything: this could either be a forged server side request, or a valid request from a browser. (It could not be a request from a browser made from an unsupported domain.)
The presence of the user cookie ensures the user is logged on, but does not ensure the user is a member of the given partner, nor that the user is viewing the correct website.
The presence of the user cookie without the CSRF validation cookie indicates forgery.
The presence of the user cookie ensures the current request is made through a browser. (Assuming a user would not enter their credentials on an unknown website, and assuming we don’t care about users using their own credentials to make some server side request.) If we also have the CSRF validation cookie, then that CSRF validation cookie was also received using a browser. Next, if we also have a CSRF token with a valid signature, and the random number in the CSRF validation cookie matches the one in that CSRF token, then the JavaScript for that token was also received during that very same earlier request during which the CSRF cookie was set, hence also using a browser. This then also implies the above JavaScript code was executed before the token was set, and that at that time the domain was valid for the given API key.
So: the server can now safely use the API key from the signed token.
If at any point the server does not trust the request, then a 403 Forbidden is returned. The widget can respond to that by showing a warning to the user.
It's not required to sign the CSRF validation cookie, as we're comparing it to the signed CSRF token. Not signing the cookie makes each HTTP request shorter, and the server validation a bit faster.
The generated CSRF token is valid indefinitely, but only in combination with the validation cookie, so effectively until the browser is closed.
We could limit the lifetime of the token's signature. We could delete the CSRF validation cookie when the user logs out, to meet the OWASP recommendation. And to not share the per-user random number between multiple partners, one could add the API key to the cookie name. But even then one cannot easily refresh the CSRF validation cookie when a new token is requested, as users might be browsing the same site in multiple windows, sharing a single cookie (which, when refreshing, would be updated in all windows, after which the JavaScript token in the other windows would no longer match that single cookie).
For those who use OAuth, see also OAuth and Client-Side Widgets, from which I got the JavaScript idea. For server side use of the API, in which we cannot rely on the JavaScript code to limit the domain, we're using secret keys instead of the public API keys.
api secret is not passed explicitly, secret is used to generate a sign of current request, at the server side, the server generate the sign following the same process, if the two sign matches, then the request is authenticated successfully -- so only the sign is passed through the request, not the secret.
This question has an accepted answer but just to clarify, shared secret authentication works like this:
Client has public key, this can be shared with anyone, doesn't
matter, so you can embed it in javascript. This is used to identify the user on the server.
Server has secret key and this secret MUST be protected. Therefore,
shared key authentication requires that you can protect your secret
key. So a public javascript client that connects directly to another
service is not possible because you need a server middleman to
protect the secret.
Server signs request using some algorithm that includes the secret
key (the secret key is sort of like a salt) and preferably a timestamp then sends the request to the service. The timestamp is to prevent "replay" attacks. A signature of a request is only valid for around n seconds. You can check that on the server by getting the timestamp header that should contain the value of the timestamp that was included in the signature. If that timestamp is expired, the request fails.
The service gets the request which contains not only the signature
but also all the fields that were signed in plain text.
The service then signs the request in the same way using the shared
secret key and compares the signatures.
I will try to answer the the question in it's original context. So question is "Is the secret (API) key safe to be placed with in JavaScript.
In my opinion it is very unsafe as it defeats the purpose of authentication between the systems. Since the key will be exposed to the user, user may retrieve information he/she is not authorized to. Because in a typical rest communication authentication is only based on the API Key.
A solution in my opinion is that the JavaScript call essentially pass the request to an internal server component who is responsible from making a rest call. The internal server component let's say a Servlet will read the API key from a secured source such as permission based file system, insert into the HTTP header and make the external rest call.
I hope this helps.
I supose you mean session key not API key. That problem is inherited from the http protocol and known as Session hijacking. The normal "workaround" is, as on any web site, to change to https.
To run the REST service secure you must enable https, and probably client authentification. But after all, this is beyond the REST idea. REST never talks about security.
What you want to do on the server side is generate an expiring session id that is sent back to the client on login or signup.
The client can then use that session id as a shared secret to sign subsequent requests.
The session id is only passed once and this MUST be over SSL.
See example here
Use a nonce and timestamp when signing the request to prevent session hijacking.

Resources