-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
[breaking] trust setting to indicate whether input text is trusted #1794
Conversation
I was thinking of a dictionary like: {
allowedProtocols: ["https", "http"],
allowedClass: /katex-.+/,
....
} but I think the function approach is better. |
docs/options.md
Outdated
@@ -26,6 +26,8 @@ You can provide an object of options as the last argument to [`katex.render` and | |||
- `"newLineInDisplayMode"`: Use of `\\` or `\newline` in display mode | |||
(outside an array/tabular environment). In strict mode, no line break | |||
results, as in LaTeX. | |||
- `trust`: `boolean` or `function` (default: `false`). If `false` (do not trust input), prevent any commands like `\includegraphics` that could enable adverse behavior, rendering them instead in `errorColor`. If `true` (trust input), allow all such commands. Provide a custom function `handler(command, ...)` to customize behavior depending on the command and possibly its arguments (e.g. a URL). A list of such commands: | |||
- `"\\includegraphics"`, with URL argument |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think of deprecating allowedProtocols
and allow setting allowed protocols for \url
and \href
here?
src/functions/includegraphics.js
Outdated
@@ -85,6 +85,10 @@ defineFunction({ | |||
alt = alt.substring(0, alt.lastIndexOf('.')); | |||
} | |||
|
|||
if (!parser.settings.isTrusted("\\includegraphics", src)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should provide context information as the second argument like:
{
type: "url",
url: "https://katex.org/image.png",
protocol: "https",
...
}
or
{
type: "html",
class: "my-class",
}
to allow setting across commands and prevent mis-parsing the url.
@ylemkimon Sorry for the long delay on looking at this. I've just pushed a new proposal where each call to the Here are some sample uses: (which maybe I should add to documentation)
I agree that this could replace |
Codecov Report
@@ Coverage Diff @@
## master #1794 +/- ##
==========================================
- Coverage 93.39% 93.34% -0.06%
==========================================
Files 79 79
Lines 4981 4988 +7
Branches 872 876 +4
==========================================
+ Hits 4652 4656 +4
- Misses 289 291 +2
- Partials 40 41 +1
Continue to review full report at Codecov.
|
I think we should be as conservative as possible, not allowing anything by default. |
@ylemkimon Agreed, safest does seem like a good default. This will break the existing release, though we can give a setting This change breaks a lot of tests, which I still need to fix. Also we should either remove or deprecate I think we should try to settle something soon, because #1842 is a pretty critical bug, so once fixed, we're going to want to release -- but I also think we can't release with |
* Check `isTrusted` in `\url` and `\href` (so now disabled by default) * Automatically compute `protocol` from `url` in `isTrusted`, so it doesn't need to be passed into every context.
@edemaine this is a big change. Thanks for tackling this! ❤️ |
docs/security.md
Outdated
with untrusted inputs; refer to [Options](options.md) for more details. | ||
* `maxSize` can prevent large width/height visual affronts. | ||
* `maxExpand` can prevent infinite macro loop attacks. | ||
* `allowedProtocols` can prevent certain protocols in URLs (e.g., with `\href`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think as we're in 0.x (major version zero) stage, we can remove allowedProtocols
without deprecation.
src/utils.js
Outdated
* Return the protocol of a URL, or "_relative" if the URL does not specify a | ||
* protocol (and thus is relative). | ||
*/ | ||
export const urlToProtocol = function(url: string): string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
protocolFromUrl
or getProtocol(FromUrl)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going to go with protocolFromUrl
since we use fooFromBar
in a number of places already.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you update the PR?
I resolved the merge conflicts which were due to this PR modifying the |
@ylemkimon I can make the changes you requested. |
Looks like there are some flow errors after the merge. I'll fix those up too. |
|
||
- Forbid specific command: `trust: (context) => context.command !== '\\includegraphics'` | ||
- Allow specific command: `trust: (context) => context.command === '\\url'` | ||
- Allow multiple specific commands: `trust: (context) => ['\\url', '\\href'].includes(context.command)` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@edemaine I really like these examples.
with untrusted inputs; refer to [Options](options.md) for more details. | ||
* `maxSize` can prevent large width/height visual affronts. | ||
* `maxExpand` can prevent infinite macro loop attacks. | ||
* `trust` can allow certain commands that are not always safe (e.g., `\includegraphics`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking of changing to something else, but I think we can just re-enable \includegraphics
once this PR is merged.
@@ -803,7 +793,8 @@ export default class Parser { | |||
throw new ParseError( | |||
"Undefined control sequence: " + text, firstToken); | |||
} | |||
result = this.handleUnsupportedCmd(); | |||
result = this.formatUnsupportedCmd(text); | |||
this.consume(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The consume
was moved out of formatUnsupported
to here.
protocol?: string, | ||
|}, | ||
"\\includegraphics": {| | ||
command: "\\includegraphics", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going to leave this in since we want to re-enable \includegraphics
once this lands.
"\\url": {| | ||
command: "\\url", | ||
url: string, | ||
protocol?: string, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While this could be restructured to dedupe the url
and protocol
we may have other commands that are insecure in other ways in the future.
@@ -21,7 +22,7 @@ export type FunctionHandler<NODETYPE: NodeType> = ( | |||
context: FunctionContext, | |||
args: AnyParseNode[], | |||
optArgs: (?AnyParseNode)[], | |||
) => ParseNode<NODETYPE>; | |||
) => UnsupportedCmdParseNode | ParseNode<NODETYPE>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had to flip the order to make flow happy. I'll add a link to the issue in the code.
src/utils.js
Outdated
* Return the protocol of a URL, or "_relative" if the URL does not specify a | ||
* protocol (and thus is relative). | ||
*/ | ||
export const urlToProtocol = function(url: string): string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going to go with protocolFromUrl
since we use fooFromBar
in a number of places already.
* should be an object with `command` field specifying the relevant LaTeX | ||
* command (as a string starting with `\`), and any other arguments, etc. | ||
* If `context` has a `url` field, a `protocol` field will automatically | ||
* get added by this function (changing the specified object). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment is great!
I renamed this PR to having [breaking] in the title as a reminder to ourselves to bump the version when publishing. @ylemkimon I think I've addressed all of your concerns. Please have another look when you have some time. |
Thanks @kevinbarabash for picking up my slack here. (And sorry I've been too busy lately to do it myself.) Given that |
test/katex-spec.js
Outdated
allowedProtocols: [], | ||
})); | ||
}); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice to replace these with tests of the corresponding trust
settings (as in the documentation examples). In general, it would be good to add trust
tests. Because trust
violations don't throw errors, you could probably just use snapshot tests... Or test for the appropriate parse node.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea. Will do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've re-added the tests but I had to refactor them a bit to be snapshot tests since \href
with trust: false
parses, but produces a different parse tree from when trust: true
is set.
I've also set the default for the unit tests to trust: false
. I can probably remove that setting though since false
is the default.
I'd like to keep this PR focused on the new |
Makes sense. We'll have the old commits anyway to guide the small changes needed for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is good to go!
Here is a draft of a
trust
setting to indicate whether the input text is trusted (and thus fix #1771), also allowing a function (like we do withstrict
) to depend on the specific function that we're worried about (advanced usage).I did not add support for an array of trusted things like I suggested in #1771, in order to keep this simple, but happy to add something like that if we want.
I also have not added any tests; wanted to see if people like this interface first.