What are the security differences between cookies with Domain vs SameSite strict? - security

When we create a cookie we can specify where it's being used by setting the domain attribute.
Set-Cookie: Foo=bar; Path=/; Secure; Domain=baz.qux.com;
The cookie above will be used along only with requests to the domain baz.qux.com.
Set-Cookie: Foo=bar; Path=/; Secure; SameSite=strict;
The cookie above omits the domain attribute, which means the domain where the cookie was set will be used (subdomains excluded, exception for IE). It also has the attribute SameSite=strict, which means:
SameSite cookies let servers require that a cookie shouldn't be sent with cross-site (where Site is defined by the registrable domain) requests, which provides some protection against cross-site request forgery attacks (CSRF).
from MDN
What are the differences in behaviour between these two cookies if both were set on the domain baz.qux.com?
How does the SameSite=strict attribute protect against CSRF that the other cookie with specified domain does not?

The Domain attribute restricts the hosts that the cookie will be sent to. The SameSite attribute restricts the origins from which the cookie may be sent.
So the first cookie:
Set-Cookie: Foo=bar; Path=/; Secure; Domain=baz.qux.com;
can be sent to baz.qux.com or any of its subdomains, regardless of the requests origin (i.e. whether sent from webpage hosted at baz.qux.com or foo.example.com)
The second cookie:
Set-Cookie: Foo=bar; Path=/; Secure; SameSite=strict;
can only be sent to baz.qux.com (since no domain specified, and ignoring IE exception,) and only when the request originates from the qux.com site (i.e it won't be sent for cross-site requests.)
This helps prevent CSRF by preventing random web sites (hacker.example.com) from performing authenticated requests to third-parties (baz.qux.com) that include session cookies.

Related

instagram basic display API get request not working?

I'm trying to do a basic get request based on the short-lived token recieved from a previous request to instagram. I know the short-lived-access-token is valid.
The account i'm testing with is a test user and the app is in development mode at facebooks end. Furthermore, the app review is currently pending but i dont think that's the issue since the account i'm testing is a test account and again - the login feature is set to development mode.
When i do the request based on the documentation:
https://developers.facebook.com/docs/instagram-basic-display-api/guides/long-lived-access-tokens/
i get the following response with status code 400:
Sorry, this content isn't available right now
based on this request format:
https://graph.instagram.com/access_token
?grant_type=ig_exchange_token
&client_secret={instagram-app-secret}
&access_token={short-lived-access-token}
Here is the full response:
HTTP/1.1 400 Bad Request
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Vary: Origin
Content-Type: application/json; charset=UTF-8
WWW-Authenticate: OAuth "Facebook Platform" "invalid_token" "Invalid OAuth access token."
Access-Control-Allow-Origin: *
Strict-Transport-Security: max-age=15552000
Pragma: no-cache
Cache-Control: no-store
Expires: Sat, 01 Jan 2000 00:00:00 GMT
x-fb-request-id: Al1knRjoI2Qw1XEVlh4b3Ku
x-fb-trace-id: GasPh1zh4bl
x-fb-rev: 1004118369
X-FB-Debug: 73PsZ2YPe6C2obr8nIdox2r2YOtNoVsuva4y2rRLvd70l06oV8kfdjOzLRhPvLDvpsmc1+5gP42Hc4Pi4AUHLw==
Date: Fri, 16 Jul 2021 04:19:09 GMT
X-FB-TRIP-ID: 1512268381
Connection: keep-alive
Content-Length: 45
Sorry, this content isn't available right now
Had this problem too, but fortunately stumbled upon the solution. What was missing for me that I wasn't requesting the instagram_graph_user_profile permission when authorizing the user.
This permission is listed as being required for the access_token endpoint, and for me made the difference between getting "Sorry, this content isn't available" and a long-lived access token.
i.e.
https://api.instagram.com/oauth/authorize
?client_id={app-id}
&redirect_uri={redirect-uri}
&scope=user_profile,user_media,instagram_graph_user_profile
&response_type=code
Exchanging access_token can be tricky sometimes. Let me walk you through another way to get the access_token.
First, we make a GET call to get the auth code. Scope depends on the permission given to the Test app.
https://www.facebook.com/v11.0/dialog/oauth?client_id={app-id}&redirect_uri={your_redirect-uri}&auth_type={rerequest}scope={email}
Now, Your Test App needs login access which further gets redirected to the URL mentioned in the test app. The URL consists of code. Copy the code and don't include #= part.
To get the access token now we make another GET request.
https://graph.facebook.com/v11.0/oauth/access_token?client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URL}&client_secret=${CLIENT_SECRET}&code=${oauth_code}
This gives you access_token. Copy the access_token and paste that in Access Token Debugger link. You will find out that this comes with no expiry date.

Cookie Initially Set with Secure Attribute loses Secure Attribute

I have non-session authentication cookies that have an expiration of 2 weeks. They are initially set with the Secure attribute. At some point these cookies are losing the Secure attribute.
Could the browser be doing this? When the cookie is first set, Secure is set and SameSite = "None". When the Secure attribute is lost, SameSite is then set to "Lax". So far, I've only noticed this happening at least two days after creating the cookie. I have noticed this in Firefox and Chrome.
I need to start setting SameSite = "Lax", so I'm going to start testing this.
More info:
MVC 3 Web App using FormsAuthentication
Login is the only way to get an auth cookie
I create a FormsAuthenticationTicket, encrypt the ticket, then use the encrypted ticket when calling
new HttpCookie("myAuthCookieName", encryptedFormsAuthenticationTicket);
Web.config is set to require Secure Cookies:
<httpCookies httpOnlyCookies="true" requireSSL="true" />

Why does Chrome allow this silent Azure OAuth authorization request but not Firefox and Edge?

Background
Webapp (SPA + WebAPI) uses Azure + OAuth + OpenID Connect to authenticate and authorize the user.
OAuth Implicit flow.
Once the access token expires, I call the Azure OAuth authorization end point to silently request a new access_token.
Authorization endpoint https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/authorize
Authorization Request
The URL to do the silent authorization request is (formatted for readability)
https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/authorize
?response_type=token id_token
&client_id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
&state=123
&scope=openid api://xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/user_impersonation
&redirect_uri=https://my-app.azurewebsites.net/index.html
&nonce=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
&prompt=none
Response
The response from all 3 browsers is a 302. But the location header in the response differs.
Chrome location (formatted for readability)
https://my-app.azurewebsites.net/index.html
#access_token=...
&token_type=Bearer
&expires_in=3599
&scope=api://xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/user_impersonation
&id_token=...
&state=123
&session_state=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Edge / Firefox location
https://my-app.azurewebsites.net/index.html
#error=login_required
&error_description=AADSTS50058 A silent sign-in request was sent but no user is signed in. The cookies used to represent the users session were not sent in the request to Azure AD. This can happen if the user is using Internet Explorer or Edge and the web app sending the silent sign-in request is in different IE security zone than the Azure AD endpoint (login.microsoftonline.com). Trace ID xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxCorrelation ID xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Timestamp 2020-01-24 08:17:33
&error_uri=https://login.microsoftonline.com/error?code=50058
&state=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Error message (from Edge / Firefox response)
A silent sign-in request was sent but no user is signed in.
The cookies used to represent the users session were not sent in the request to Azure AD.
This can happen if the user is using Internet Explorer or Edge
and the web app sending the silent sign-in request is in different
IE security zone than the Azure AD endpoint (login.microsoftonline.com).
The message from the error URI https://login.microsoftonline.com/error?code=50058 is
Session information is not sufficient for single-sign-on.
This means that a user is not signed in.
This is a common error that's expected when a user is unauthenticated and has not yet signed in.
If this error is encountered in an SSO context where the user has previously signed in,
this means that the SSO session was either not found or invalid.
This error may be returned to the application if prompt=none is specified
Cookies
I noticed the cookies sent and received by Chrome differ from the cookies sent and received by Edge / Firefox.
Chrome request cookies (17)
x-ms-gateway-slice=...;
stsservicecookie=...;
AADSSO=...;
esctx=...;
brcap=.;
clrc=...;
wlidperf=...;
MSCC=...;
ESTSAUTHLIGHT=...;
ESTSSC=...;
ESTSAUTHPERSISTENT=...;
ESTSAUTH=...;
ch=...;
buid=...;
CCState=...;
SignInStateCookie=...;
fpc=...
Chrome response cookies (11)
ESTSAUTHPERSISTENT=...; domain=.login.microsoftonline.com; expires=Thu, 23-Apr-2020 08:18:32 GMT; path=/; secure; HttpOnly; SameSite=None
ESTSAUTH=...; domain=.login.microsoftonline.com; path=/; secure; HttpOnly; SameSite=None
ESTSAUTHLIGHT=...; path=/; secure; SameSite=None
ch=...; domain=.login.microsoftonline.com; expires=Thu, 23-Apr-2020 08:18:32 GMT; path=/; secure; SameSite=None
ESTSSC=...; path=/; secure; HttpOnly; SameSite=None
buid=...; expires=Sun, 23-Feb-2020 08:18:32 GMT; path=/; secure; HttpOnly; SameSite=None
CCState=...; domain=.login.microsoftonline.com; expires=Sun, 23-Feb-2020 08:13:32 GMT; path=/; secure; HttpOnly; SameSite=None
SignInStateCookie=...; path=/; secure; HttpOnly; SameSite=None
fpc=...; expires=Sun, 23-Feb-2020 08:18:32 GMT; path=/; secure; HttpOnly; SameSite=None
x-ms-gateway-slice=...; path=/; SameSite=None; secure; HttpOnly
stsservicecookie=...; path=/; secure; HttpOnly; SameSite=None
No request cookies in Edge / Firefox.
Edge / Firefox response cookies (4)
buid=...; expires=Sun, 23-Feb-2020 08:24:39 GMT; path=/; secure; HttpOnly; SameSite=None
fpc=...; expires=Sun, 23-Feb-2020 08:24:39 GMT; path=/; secure; HttpOnly; SameSite=None
x-ms-gateway-slice=...; path=/; SameSite=None; secure; HttpOnly
stsservicecookie=...; path=/; SameSite=None; secure; HttpOnly
Versions
Chrome version: 79.0.3945.130
Edge version: 44.18362.449.0
Firefox version: 72.0.2
Questions
Why does Chrome allow this call to https://login.microsoftonline.com to silently request an access token but on Firefox and Edge the call fails?
Why does Chrome include the above requests cookies but not Firefox and Edge?

Cache-Control private in kiosk mode

Suppose I expose a REST service (over HTTPS) that uses bearer token authentication (JWT) and responds to a GET request with the Cache-Control: private header.
Now suppose my application is used in kiosk mode (multiple users use same browser session as same OS user, think internet cafe or something). User1 makes an authenticated request to a resource.
GET /api/resource
Authorization: bearer <token1>
The response starts with:
HTTP/1.1 200 OK
Cache-Control: private
Now, User1 signs out of my application and User2 signs in. The browser makes a request to the same resource on her behalf (but with a different JWT token).
GET /api/resource
Authorization: bearer <token2>
Now my question is, would the browser consider serving this from cache as it's the same request from the same OS user? Or would the browser consider the Authorization value in that decision?
If the former, would a Vary: Authorization header in the original response change that behavior.
Per RFC 2616, Section 14.9.1, the Cache-Control: private response header will indeed mean that your multiple kiosk users, sharing the same browser session, will all get the same cached response.
And yes, adding a Vary: Authorization response header would help, as indicated by Section 13.6 of RFC 2616; it tells the cache to keep/select from among different "representations" of the resource, based on the request headers listed in the Vary response header value.
Hope this helps!

Cannot access OpenId UserInfo endpoint on Azure (AADSTS90010: JWT tokens cannot be used with the UserInfo endpoint)

I'm trying to access the OpenId UserInfo endpoint for a user on an Office365 Azure tenant, with the following GET:
GET https://login.windows.net/common/openid/userinfo HTTP/1.1
Authorization: Bearer eyJ0eXAiOiJ(...remainder deleted for brevity...)
Host: login.windows.net
The response fails with "400 Bad Request", and a more specific error "AADSTS50063: Credential parsing failed. AADSTS90010: JWT tokens cannot be used with the UserInfo endpoint"
HTTP/1.1 400 Bad Request
Cache-Control: no-cache, no-store
Pragma: no-cache
Content-Type: text/html
Expires: -1
Server: Microsoft-IIS/8.5
x-ms-request-id: ef5c8a50-69b5-40f1-ac5f-9c0fc5180aa2
x-ms-gateway-service-instanceid: ESTSFE_IN_6
X-Content-Type-Options: nosniff
Strict-Transport-Security: max-age=31536000; includeSubDomains
P3P: CP="DSP CUR OTPi IND OTRi ONL FIN"
WWW-Authenticate: Bearer correlation_id="e5c613a0-0a21-40e1-9ef6- eacf77580608", error="invalid_request", error_codes="[50063, 90010]", error_description="AADSTS50063: Credential parsing failed. AADSTS90010: JWT tokens cannot be used with the UserInfo endpoint.%0d%0aTrace ID: ef5c8a50-69b5-40f1-ac5f-9c0fc5180aa2%0d%0aCorrelation ID: e5c613a0-0a21-40e1-9ef6-eacf77580608%0d%0aTimestamp: 2015-02-20 14:13:42Z", timestamp="2015-02-20 14:13:42Z", trace_id="ef5c8a50-69b5-40f1-ac5f-9c0fc5180aa2"
Set-Cookie: x-ms-gateway-slice=productionb; path=/; secure; HttpOnly
Set-Cookie: stsservicecookie=ests; path=/; secure; HttpOnly
X-Powered-By: ASP.NET
Date: Fri, 20 Feb 2015 14:13:40 GMT
Content-Length: 0
The bearer token used is a non-expired access token that works fine for other operations, such as retrieving Exchange emails.
Furthermore, when I use an identical GET to the openid userinfo endpoint at "https://www.googleapis.com/plus/v1/people/me/openIdConnect" (as part of a gmail access scenario), it works fine
Am I doing anything wrong here? Thanks for any help!
Some extra info:
-Already tried using the id_token instead of the access_token, but this makes no difference.
-the Oauth scopes used are "profile email"
-the resources requested are "https://outlook.office365.com/"
-the client application is a native app and has enabled all delegated permissions for both "Windows Azure AD" and "Office 365 Exchange Online"
The Azure AD user info endpoint does not support the use of the regular JWT access tokens at this time. Instead, you can acquire a user info specific access token by not specifying any resource in a request to the token endpoint. You can think of the user info endpoint as a resource in its own right, which requires a special token format.
For example, in the authorization code case:
GET request to https://login.windows.net/common/oauth2/authorize?... without a resource parameter, and acquire an authorization_code
POST request to https://login.windows.net/common/oauth2/token using the authorization_code, also without a resource parameter. Receive an access token for the user info endpoint.
GET request to https://login.windows.net/common/openid/userinfo passing the access token in the header as Authorization: Bearer AAAB(...rest of token...)

Resources