[breaking] trust setting to indicate whether input text is trusted#1794
[breaking] trust setting to indicate whether input text is trusted#1794k4b7 merged 15 commits intoKaTeX:masterfrom
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
| (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.
What do you think of deprecating allowedProtocols and allow setting allowed protocols for \url and \href here?
src/functions/includegraphics.js
Outdated
| alt = alt.substring(0, alt.lastIndexOf('.')); | ||
| } | ||
|
|
||
| if (!parser.settings.isTrusted("\\includegraphics", src)) { |
There was a problem hiding this comment.
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.
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.
protocolFromUrl or getProtocol(FromUrl)
There was a problem hiding this comment.
I'm going to go with protocolFromUrl since we use fooFromBar in a number of places already.
|
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)` |
| 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.
I was thinking of changing to something else, but I think we can just re-enable \includegraphics once this PR is merged.
| } | ||
| result = this.handleUnsupportedCmd(); | ||
| result = this.formatUnsupportedCmd(text); | ||
| this.consume(); |
There was a problem hiding this comment.
The consume was moved out of formatUnsupported to here.
| protocol?: string, | ||
| |}, | ||
| "\\includegraphics": {| | ||
| command: "\\includegraphics", |
There was a problem hiding this comment.
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.
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.
| args: AnyParseNode[], | ||
| optArgs: (?AnyParseNode)[], | ||
| ) => ParseNode<NODETYPE>; | ||
| ) => UnsupportedCmdParseNode | ParseNode<NODETYPE>; |
There was a problem hiding this comment.
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.
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). |
|
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 |
| allowedProtocols: [], | ||
| })); | ||
| }); | ||
|
|
There was a problem hiding this comment.
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.
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 |
ylemkimon
left a comment
There was a problem hiding this comment.
I think this is good to go!
Here is a draft of a
trustsetting 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.