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

Connect: Enable font configuration #21965

Merged
merged 11 commits into from
Feb 22, 2023
Merged

Conversation

gzdunek
Copy link
Contributor

@gzdunek gzdunek commented Feb 17, 2023

Part of #21914

As we discussed in the last design session, we do not want to configure the main font of the application. I think in this case the best option is to remove it from the config schema completely.

Input validation

We will let users provide their own fonts by configuring them in app_config.json. This creates the security problem of injecting arbitrary CSS.

I prepared a test string ("Arial;} html {background-color: red;}") and passed it to fontFamily.mono to see if it is injected into the app.

At first I started with CSS.escape, as advised in styled-components. I assumed that I should pass only the value I wanted to sanitize and that's all. Unfortunately, it turned out that this function also escapes commas and single quotes, so the result of:

CSS.escape("Menlo, Monaco, 'Courier New', monospace")

was

font-family: Menlo\,\ Monaco\,\ \'Courier\ New\'\,\ monospace;

which didn't work in a browser.
(But maybe I did something wrong with CSS.escape?)

Then I found this great article https://frontarm.com/james-k-nelson/how-can-i-use-css-in-js-securely/ and tried the approach with style. I think is this the way to go. When an invalid string is passed as a style, it just becomes empty.
I'm only afraid that this solution is a bit "hacky" (mainly in xterm), but I didn't find anything better :(

Remote content

From what I have tested, CSP protects us from loading some remote content using url().
And for font-family, url() is not even an allowed value.

It seems that the worst thing a malicious CSS can do is changing the styles, but I think that input validation is a good thing anyway.

Copy link
Member

@ravicious ravicious left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the link to that frontarm.com article, it gives a comprehensive overview of the attack vectors I was worried about.

The solution you chose seems to be a good fit and you provided a detailed justification as to why it's secure. 👍

I'll give it a try on Monday as for some reason my brain has huge problems with switching contexts today.

Until then, I've read through some additional resources when reviewing this PR to find another source which would confirm that doing this through style is safe. I couldn't find anything which would dispute this claim. The only thing is that our solution would potentially allow passing url(…) but as you said, it's not supported for font-family. Take a look at those resources though, maybe you'll find something that I missed.

web/packages/teleterm/src/ui/ThemeProvider/theme.ts Outdated Show resolved Hide resolved
@zmb3 zmb3 requested a review from jentfoo February 17, 2023 15:52
@zmb3
Copy link
Collaborator

zmb3 commented Feb 17, 2023

@jentfoo added you as a reviewer to this one - would appreciate your review from a security perspective.

@ravicious
Copy link
Member

For the record, the attack vector I'm thinking of is a malicious actor modifying app_config.json of the user to inject CSS to set up other attacks. They'd need to already have an access to the victim's computer.

@ravicious
Copy link
Member

@ravicious ravicious self-requested a review February 20, 2023 09:49
@gzdunek
Copy link
Contributor Author

gzdunek commented Feb 20, 2023

I took a look at the links you provided @ravicious and yes, they seem to confirm what we think.

This talks about the expression directive which I think was since removed from CSS? The post is several years old.

From OWASP:

From my experience, calling the expression() function from an execution context (JavaScript) has been disabled.


However, I spend some time today trying to find more resources regarding setting style in React, and this post was interesting: facebook/react#3473 (comment)

It's also important to document that style={{backgroundColor: userColor}} is also exploitable and allows injection of arbitrary CSS. It won't stop the problem, but just having it publicly documented is a big step (seeing as it's unlikely that we can ever out-right prevent it when targeting HTML).

I assume it refers to setting multiple properties as a "one" property: border: '1px solid black; background: red'.
However it looks like it was fixed a long time ago facebook/react#5878 (comment) (and I couldn't repro this).

From what I see React sets style using JS API. I was worried that it uses some weird tricks to set the styles, but since it simply uses the API to do it, the browser should protect us.

While digging in React codebase, I found this comment, but I think it relates to things like url?

@ravicious
Copy link
Member

Good finds there, Grzegorz.

While digging in React codebase, I found this comment, but I think it relates to things like url?

I cloned the React repo and it looks like dangerousStyleValue is used only in two places: createDangerousStringForStyles and setValueForStyles. The first one is used only in dev mode when using SSR. It constructs the whole style string, such as display: block; color: green; which I assume is then returned from the server, so here it's totally possible to inject arbitrary CSS.

setValueForStyles uses dangerousStyleValue too, but it sets the style using style[styleName] = styleValue which is safe as far as I understand.

@ravicious
Copy link
Member

ravicious commented Feb 20, 2023

It looks like Powerline glyphs work just fine when choosing a font which supports them:

https://gist.github.com/gdetrez/5845092

Powerline glyphs in Connect

@ravicious
Copy link
Member

Should we also let people pick terminal font size while we're at it? When I'm changing my terminal/editor font, I often adjust the size too because different fonts have different actual line heights and so on.

Copy link
Member

@ravicious ravicious left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, though I'd wait for @jentfoo before merging.

Any plans for docs and test plan updates? I was going to suggest that since the web code now lives in the same repo as docs, it could be a good idea to include doc changes as well. But on a second thought I'm not sure about it – submitting a separate PR with docs + test plan only shouldn't make that much of a difference.

@gzdunek
Copy link
Contributor Author

gzdunek commented Feb 21, 2023

LGTM, though I'd wait for @jentfoo before merging.

👍

Any plans for docs and test plan updates? I was going to suggest that since the web code now lives in the same repo as docs, it could be a good idea to include doc changes as well. But on a second thought I'm not sure about it – submitting a separate PR with docs + test plan only shouldn't make that much of a difference.

I think it is better to send a separate PR with changes to the docs, so the docs team will review them at once.
I will push a PR covering the config in Connect after implementing all parts.

Copy link
Contributor

@jentfoo jentfoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for looping me in, and thank you @gzdunek for looking into the mechanics of this closer and help answer some of my questions in DM.

This appears to be safe to me also. The concerns I had, @gzdunek helped explain away, and I do agree with him that it appears any script injection here would be a compromise of the contract the browser is presenting to us.

Whenever relying on browser protections to that level there is of course risk that out of date browsers may be at risk. However I don't believe that needs to be considered as part of this change.

* Read more https://frontarm.com/james-k-nelson/how-can-i-use-css-in-js-securely/.
*/
'terminal.fontFamily': z.string().default(defaultTerminalFont),
'terminal.fontSize': z.number().int().min(5).max(100).default(15),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah damn, forgot to say that I don't think we need to be as strict here, we could do like min 1 and max, idk, 256. I'd rather allow super tiny values since it doesn't change anything for us but might enable some niche use cases for the users.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can do it.

@gzdunek gzdunek added this pull request to the merge queue Feb 22, 2023
Merged via the queue into master with commit 8c08211 Feb 22, 2023
@public-teleport-github-review-bot

@gzdunek See the table below for backport results.

Branch Result
branch/v12 Create PR

@gzdunek gzdunek deleted the gzdunek/allow-font-configuration branch March 20, 2023 16:28
@ravicious ravicious mentioned this pull request Mar 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants