5 ms·
Server components seem like a surefire way to leak secrets to clients. Can we please go back to separating clients from servers? Or, at the very least, treat y
by brap 3y ago
Server components seem like a surefire way to leak secrets to clients.
Can we please go back to separating clients from servers? Or, at the very least, treat your rendering server as just another untrusted client.
- n2d4 3y agoWhy are your secrets in the source code in the first place? Put them into environment variables, which I hope aren't exposed by your infrastructure by default. If the secret you're protecting is the source code itself, that's a valid concern, though React offers `server-only` for that purpose. The boundary between server and client is pretty explicit and you can't pass props from one to the other accidentally, but admittedly, that won't stop an inexperienced developer refactoring the codebase at 3am to mess up, I guess.
- brap 3y agoThis isn’t about leaking the source code. Secrets could leak through environment variables too. It actually doesn’t matter how the server got a hold of the secret. If the value is in closure for some function the client has to execute (such as the component render function, or any client side effect etc), it will be sent to the client, silently. There are actually documented instances of this already happening. And this is just one problem that was already discovered.
- n2d4 3y agoYou can't define a client component like that, it's just not possible. Server and client are two different scripts with different entrypoints, with no shared closures. Are you referring to Server Actions? That's a feature separate to RSC, from what I can tell not supported by the framework in TFA, and the React maintainers are aware of what you mentioned. Server Actions are currently unreleased and undocumented (though NextJS already supports them in alpha), and you can expect their behaviour to change in significant ways. For those who don't know, essentially the following Server Actions code: const serverComponent = () => { const secret = "my secret"; const myServerAction = () => { "use server"; submitSecretToDB(secret); } return <button onClick={myServerAction} /> }; will roughly render to the following HTML: <button onClick="post('/myServerAction', {secret: 'my secret'})"></button> which is unexpected because you probably wouldn't expect RSCs to leave behind this value used in code (as RSCs are executed on the server). But this is not the RSC's fault, it's the server action which is compiled down in an unintuitive way. React devs have discussed potential fixes (eg. encryption) on Twitter, I'm not sure whether they've been implemented yet or not.