Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Could this tool be improved to warn new devs about potential bad anti-patterns Astro SSR? #65

Open
alexanderniebuhr opened this issue May 17, 2023 · 13 comments

Comments

@alexanderniebuhr
Copy link

alexanderniebuhr commented May 17, 2023

I think I found a way to leak variables to the client in Astro using Islands with client:only...

  • Throw if non-client variables are leaked inside serialised props. Obviously this allows server variables if code is run on server to generate HTML. However now I can just add a server variable as an prop for an UI Component and it will show up in plain text in the HTML. This is an leak, which should be prevented.
  • If I import the validation function inside a UI Component and then use client:only island, I will get errors and no render if I try to access an server variable, which is expected. But the validation function is in the js island chunk. So some can open dev tools, look at the js chunk and find the variables.

Originally posted by @alexanderniebuhr in #60 (comment)

@chungweileong94
Copy link
Contributor

I'm not sure if I understand it correctly, it would be good if you can create a small example repo that can reproduce the problem that you describe.

There's always a way to leak ENV with/without t3-env. For instance, if you try to access a server-only ENV on server then pass it to client-side, this will leak the env for sure.

@alexanderniebuhr
Copy link
Author

For instance, if you try to access a server-only ENV on server then pass it to client-side, this will leak the env for sure.

That's actually the case I tried to describe with the first bullet. I am wondering if there is a way to at least warn the user about this. I am a more advance user and know the patterns to avoid this, but as I am currently working on educational content for new-comers. I wanted to include t3-env, and it would be great if the tool can not experienced devs about bad pattern or potential leak either in SSR Html or serialised component props.

Not sure if it is feasible, but maybe the tool could somehow parse and check if the env is accessed in a way, which could leak.

@alexanderniebuhr alexanderniebuhr changed the title Found leaked variables in Astro Island Could this tool be improved to warn new devs about potential bad patterns and leaks in Astro? May 21, 2023
@chungweileong94
Copy link
Contributor

Not sure if it is feasible, but maybe the tool could somehow parse and check if the env is accessed in a way, which could leak.

Well, the tool kinda did, but not quite. It throws an error if you try to use a server env on client, but of course that's not enough to prevent people from leaking the env.

Maybe this is something that ESLint can help, but again there's too many ways/patterns to leak server env, which I think this is something people should really know and learn how to prevent it. But I agree with you that it would be good if the tool can prevent this from the first place.

@juliusmarminge
Copy link
Member

I dont see how though? ESLint maybe can detect this?

@alexanderniebuhr
Copy link
Author

alexanderniebuhr commented May 23, 2023

I dont see how though?

In Astro, we should know which parts of the code are SSR. I would think the assumption that everything is SSR except specifically set an client directive like client:, could be good enough.

If someone uses env variables in these places, it should check if the user tries to access client or server vars and print a warning if server vars are used. The only question I have, how much parsing is necessary and does it impact perf.

@intagaming
Copy link

intagaming commented May 23, 2023

Tried searching for my server variables in the client bundles. Indeed I can see my build-time server-side variables leaked in the bundle, but all the runtime server-side variables are not bundled. I think it's important to point out the specific types of variables here, as:

  • The runtime server-side variables can't be leaked into the JS bundles because they aren't available at build time.
  • The runtime server-side variables are possible to be leaked into the HTML at runtime.

So the problems to solve here are:

  • Build-time server-side variables aremight be leaked into the JS bundles at build time. -> Actually not a problem anymore if you don't use whatever you Vite define inside t3-env.ts. For me instead of using process.env.XXX I use import.meta.env.XXX.
  • Runtime server-side variables are leaked into the HTML at runtime.

The former might need us to separate different env.ts files for the client and the server. Maybe env.client.ts and env.server.ts. Then make sure env.server.ts is not being imported in the client JS bundles. The latter is like a kind of SQL-injection that either needs dev's attention or linting like discussed on above comments.

@alexanderniebuhr
Copy link
Author

alexanderniebuhr commented May 23, 2023

build-time server-side variables leaked in the bundle

I saw the built-time envs in my bundle too, after I used your setup.
But I changed my implementation a little bit (#60 (comment)), and now it seems there are not visible in the bundle anymore. It seems vite takes care of them.

The runtime leak is definitely something the dev has to prevent, and not an technical issue. But I think if the tool could still warn about this, it would be great!

@intagaming
Copy link

intagaming commented May 23, 2023

Lesson learned: One must build the project, then go to the DevTools and search for their envs on the client, just to be sure. Maybe even inspect the server bundle in dist/server/chunks/pages/ to see if the build-time envs are in place.

Luckily my project has not gone to the production yet. Before any linting plugin exists, just make sure to double check. You can't trust linting tools to go eslint --autofix and expect them to do it correctly forever. Linting tools have limitations too. Users of Astro SSR or any SSR framework, be warned.

Also take a look at https://github.com/withastro/astro/blob/main/packages/astro/src/vite-plugin-env/index.ts. It is a bit magical what is has done on top of Vite. Oh and I have some documentation about all these in my issue here #60.

@juliusmarminge
Copy link
Member

Can you explain what variables are leaked and how? The framework shouldn't let server-side variables be defined on the client, no matter what file you're using it in. There is no way i can use process.env.DATABASE_URL on the client, and thus not env.DATABASE_URL either.

What am I missing?

@intagaming
Copy link

intagaming commented May 23, 2023

Can you explain what variables are leaked and how? The framework shouldn't let server-side variables be defined on the client, no matter what file you're using it in. There is no way i can use process.env.DATABASE_URL on the client, and thus not env.DATABASE_URL either.

What am I missing?

It's actually a little bit of an anti-pattern: if you use Vite's define and use the defined thing in t3-env.ts, then that thing will be included both in the client and the server. The purpose was to define build-time server-side variables by defining process.env.XXX with something so that Vite will go replace it at build time, but actually you can just do that and use import.meta.env.XXX instead of using process.env.XXX or whatever you defined in Vite's define.

Actually that has nothing to do with t3-env at all. Just a Vite thing. I wanted to validate that at build time via t3-env, but that isn't related to the above "leak" too much.

The second "leakability" is rendering the server variables in the HTML, which can happen everywhere, not just client:only. You can just read it in the Astro's frontmatter and render it.

That also isn't related to t3-env at all, and can happen anywhere there is server-side rendering involved. So I guess nothing can be done from t3-env except trying to provide a kind of SQL injection prevention but for env vars.

@alexanderniebuhr
Copy link
Author

alexanderniebuhr commented May 23, 2023

Can you explain what variables are leaked and how?

As far as I can tell, if you setup your envs for Astro correctly nothing is leaked per definition.
But you can use process.env.DATABASE_URL in code which is server-side rendered and on the server it will replace this with the raw value. This raw value is sent to the client and rendered from HTML. This is something you can do in any framework, and you can't fully prevent, but helping devs catch this would be great. So this issue pivoted to discussion a potential solution to warn users about this anti-pattern.

@alexanderniebuhr alexanderniebuhr changed the title Could this tool be improved to warn new devs about potential bad patterns and leaks in Astro? Could this tool be improved to warn new devs about potential bad anti-patterns Astro SSR? May 23, 2023
@juliusmarminge
Copy link
Member

Ok so the same would be true for RSC if you store a value from env to a variable and passet as prop. Same can be true if you return a value in an api endpoint.

I dont think its the job of t3-env to present this. Maybe we can make a @t3-env/eslint-plugin that can analyze the code and see if a pattern like this is present and warn about it? Would be a pretty cool thing

@alexanderniebuhr
Copy link
Author

alexanderniebuhr commented May 23, 2023

Ok so the same would be true for RSC if you store a value from env to a variable and passet as prop. Same can be true if you return a value in an api endpoint.

Correct!

I dont think its the job of t3-env to present this. Maybe we can make a @t3-env/eslint-plugin that can analyze the code and see if a pattern like this is present and warn about it?

Agree, that it would be pretty cool to have and it will be a lint warning instead of an actual thrown error. However not sure if an eslint plugin would be the best solution. Not everyone uses eslint (I use rome tools).

I wonder if this linting step could be included in t3-env as an opt-in configuration option? So it can be chosen to be used and it will offer this to devs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants