bridge icon indicating copy to clipboard operation
bridge copied to clipboard

cache-control: max-age=0, private not working and causing info leak

Open antlionguard opened this issue 2 years ago • 6 comments

Environment



Reproduction

I cannot reproduce because this situation happens very comlex code base.

Describe the bug

Although cache-control: max-age=0, private is set in Response Header, nuxt caches this request and this response is returned to other users. Because of this, I am experiencing an info leak.

This only happening on ssr.

Additional context

Our project running in docker and AWS.

Logs

No response

antlionguard avatar Aug 01 '22 21:08 antlionguard

@antlionguard Would you provide a simple reproduction showing how a route ends up being cached? Have you enabled nitro caching on any routes?

danielroe avatar Aug 03 '22 13:08 danielroe

@antlionguard Would you provide a simple reproduction showing how a route ends up being cached? Have you enabled nitro caching on any routes?

I will try to create reproduction. And i don't use nitro. Nitro is set false in bridge config.

antlionguard avatar Aug 04 '22 11:08 antlionguard

If you are not using nitro then this is almost certainly not an issue with Bridge. But will happily look at reproduction just in case!

danielroe avatar Aug 04 '22 13:08 danielroe

If you are not using nitro then this is almost certainly not an issue with Bridge. But will happily look at reproduction just in case!

Oh probably there's completely different problem exist from pinia. Not related with "cache-control" header or axios, nitro etc.

I have a question. Pinia has any ssr caching mechanism? Do you know this?

There's simple code example from my nuxt-bridge project.

Part of <script setup> Country Select Component (This component wrapped by <client-only>. That's an important point):

...
// Country Fetch
const isFetching = ref(true);
const countryOptions = ref();
typeStore.fetchCountryList().then(() => {
  countryOptions.value = typeStore.countryList;
  isFetching.value = false;
});
...

countryList method inside typeStore (this is pinia store):

...
    async fetchCountryList() {
      try {
        if (isEmpty(this.countryList)) {
          const { data } = await this.$nuxt.$api.commonServicesV2.fetchCountryList();
          this.countryList = data.data;
        }
      } catch (error) {
           **********
      }
    },
...

When i refresh the page i cannot see in network tab commonServicesV2.fetchCountryList was called but countryList is filled. It seems like pinia states was stored on server side. That's very interesting to me. Or there is something I missed about pinia? Shouldn't pinia states only work on the clientside and not be cached?

antlionguard avatar Aug 04 '22 14:08 antlionguard

Ah. Wrapping in <client-only> doesn't mean that those components don't load on the server - it only means that no HTML is emitted. They may all still run. So if you are initialising and filling a store there, it will be filled even though the HTML isn't rendered.

danielroe avatar Aug 04 '22 14:08 danielroe

I'm facing a problem similar to https://github.com/aws-amplify/amplify-js/discussions/7611 Maybe this reproduction will help to solve problem.

And i added cache-control header and that's didn't work. I removed all ssr fetching for user information and ssr authentication for temporarily until this problem is fixed.

And i'm trying to create minimal reproduction.

antlionguard avatar Aug 05 '22 11:08 antlionguard

Oh that's not related with headers or caching.

auth-data-load middleware -> image

The code i marked causing problem. If i try read cookie on ssr nuxt(or node idk) returns another user token if both users refresh same time. Any ideas for this? @danielroe am i missing something? Or is this usage is bad practice?

antlionguard avatar Sep 08 '22 12:09 antlionguard

That sounds cross-request state pollution and I would investigate pinia in that case. It doesn't sound like a Bridge issue.

danielroe avatar Sep 08 '22 12:09 danielroe

That sounds cross-request state pollution and I would investigate pinia in that case. It doesn't sound like a Bridge issue.

https://vuejs.org/guide/scaling-up/ssr.html#cross-request-state-pollution

There's some recommendations here but i couldn't figure out how to do in nuxt.

antlionguard avatar Sep 08 '22 12:09 antlionguard

It shouldn't be something you need to do. Both Nuxt + pinia should ensure this. Would you create a minimal reproduction so I can look into it further? :pray:

danielroe avatar Sep 08 '22 12:09 danielroe

It shouldn't be something you need to do. Both Nuxt + pinia should ensure this. Would you create a minimal reproduction so I can look into it further? 🙏

Here's the reproduction -> https://github.com/antlionguard/cross-request-state-pollution-pinia-nuxt

Reproduction steps:

  1. install deps.
  2. yarn build and yarn start (because this not happening on development)
  3. open 2 browser (i tried with firefox and chrome)
  4. press set token button in the browser on the right
  5. and refresh left side browser and after that refresh browser on the right asap (refresh order is important)

example image

reproduction

antlionguard avatar Sep 08 '22 14:09 antlionguard

The issue is that you are defining your state outside of the factory function:

const InitialAuthState: AuthState = {
  token: '',
};

export const useAuthStore = defineStore('auth', {
  state: (): AuthState => InitialAuthState,
})

That is why it is shared.

Although the factory function is called fresh each time, it returns the same object. The point of a factory function is to return a different object each time it's called.

danielroe avatar Sep 08 '22 14:09 danielroe