Skip to content

Commit bfc87c0

Browse files
committed
Use CSP to block inline JS content in editor (#3939)
* Revert "Sanitize field content in editor" This reverts commit 1c15690. * Use CSP to block inline JS content in editor This blocks inline scripts, scripts in the media folder, and handlers like onclick in the editor. This is nicer than the previous solution - it doesn't make any permanent changes, and leaves other content like SVGs alone. Thanks to Nil Admirari for the suggestion. (cherry picked from commit ddb8573)
1 parent e9dfb7a commit bfc87c0

File tree

7 files changed

+23
-66
lines changed

7 files changed

+23
-66
lines changed

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@
6969
"bootstrap-icons": "^1.10.5",
7070
"codemirror": "^5.63.1",
7171
"d3": "^7.0.0",
72-
"dompurify": "^3.2.5",
7372
"fabric": "^5.3.0",
7473
"hammerjs": "^2.0.8",
7574
"intl-pluralrules": "^2.0.0",

qt/aqt/mediasrv.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,14 +141,17 @@ def set_page_html(
141141
) -> None:
142142
self._legacy_pages[id] = LegacyPage(html, context)
143143

144+
def get_page(self, id: int) -> LegacyPage | None:
145+
return self._legacy_pages.get(id)
146+
144147
def get_page_html(self, id: int) -> str | None:
145-
if page := self._legacy_pages.get(id):
148+
if page := self.get_page(id):
146149
return page.html
147150
else:
148151
return None
149152

150153
def get_page_context(self, id: int) -> PageContext | None:
151-
if page := self._legacy_pages.get(id):
154+
if page := self.get_page(id):
152155
return page.context
153156
else:
154157
return None
@@ -740,8 +743,17 @@ def _handle_dynamic_request(req: DynamicRequest) -> Response:
740743

741744
def legacy_page_data() -> Response:
742745
id = int(request.args["id"])
743-
if html := aqt.mw.mediaServer.get_page_html(id):
744-
return Response(html, mimetype="text/html")
746+
page = aqt.mw.mediaServer.get_page(id)
747+
if page:
748+
response = Response(page.html, mimetype="text/html")
749+
# Prevent JS in field content from being executed in the editor, as it would
750+
# have access to our internal API, and is a security risk.
751+
if page.context == PageContext.EDITOR:
752+
port = aqt.mw.mediaServer.getPort()
753+
response.headers["Content-Security-Policy"] = (
754+
f"script-src http://127.0.0.1:{port}/_anki/"
755+
)
756+
return response
745757
else:
746758
return _text_response(HTTPStatus.NOT_FOUND, "page not found")
747759

ts/editor/NoteEditor.svelte

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
132132
}
133133
134134
for (const [index, [, fieldContent]] of fs.entries()) {
135-
fieldStores[index].set(sanitize(fieldContent));
135+
fieldStores[index].set(fieldContent);
136136
}
137137
138138
fieldNames = newFieldNames;
@@ -413,7 +413,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
413413
} from "../routes/image-occlusion/store";
414414
import CollapseLabel from "./CollapseLabel.svelte";
415415
import * as oldEditorAdapter from "./old-editor-adapter";
416-
import { sanitize } from "$lib/domlib";
417416
418417
$: isIOImageLoaded = false;
419418
$: ioImageLoadedStore.set(isIOImageLoaded);

ts/lib/domlib/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,4 @@ export * from "./content-editable";
55
export * from "./location";
66
export * from "./move-nodes";
77
export * from "./place-caret";
8-
export * from "./sanitize";
98
export * from "./surround";

ts/lib/domlib/sanitize.ts

Lines changed: 0 additions & 10 deletions
This file was deleted.

ts/licenses.json

Lines changed: 6 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,6 @@
5757
"path": "node_modules/@tootallnate/once",
5858
"licenseFile": "node_modules/@tootallnate/once/LICENSE"
5959
},
60-
"@types/[email protected]": {
61-
"licenses": "MIT",
62-
"repository": "https://github.com/DefinitelyTyped/DefinitelyTyped",
63-
"path": "node_modules/@types/trusted-types",
64-
"licenseFile": "node_modules/@types/trusted-types/LICENSE"
65-
},
6660
6761
"licenses": "BSD-3-Clause",
6862
"repository": "https://github.com/jsdom/abab",
@@ -101,8 +95,8 @@
10195
"repository": "https://github.com/TooTallNate/node-agent-base",
10296
"publisher": "Nathan Rajlich",
10397
"email": "[email protected]",
104-
"path": "node_modules/http-proxy-agent/node_modules/agent-base",
105-
"licenseFile": "node_modules/http-proxy-agent/node_modules/agent-base/README.md"
98+
"path": "node_modules/agent-base",
99+
"licenseFile": "node_modules/agent-base/README.md"
106100
},
107101
108102
"licenses": "MIT",
@@ -442,14 +436,6 @@
442436
"path": "node_modules/domexception",
443437
"licenseFile": "node_modules/domexception/LICENSE.txt"
444438
},
445-
446-
"licenses": "(MPL-2.0 OR Apache-2.0)",
447-
"repository": "https://github.com/cure53/DOMPurify",
448-
"publisher": "Dr.-Ing. Mario Heiderich, Cure53",
449-
"email": "[email protected]",
450-
"path": "node_modules/dompurify",
451-
"licenseFile": "node_modules/dompurify/LICENSE"
452-
},
453439
454440
"licenses": "ISC",
455441
"path": "node_modules/canvas"
@@ -586,14 +572,6 @@
586572
"path": "node_modules/lodash-es",
587573
"licenseFile": "node_modules/lodash-es/LICENSE"
588574
},
589-
590-
"licenses": "ISC",
591-
"repository": "https://github.com/isaacs/node-lru-cache",
592-
"publisher": "Isaac Z. Schlueter",
593-
"email": "[email protected]",
594-
"path": "node_modules/lru-cache",
595-
"licenseFile": "node_modules/lru-cache/LICENSE"
596-
},
597575
598576
"licenses": "MIT",
599577
"repository": "https://github.com/markedjs/marked",
@@ -790,16 +768,16 @@
790768
"repository": "https://github.com/jsdom/whatwg-url",
791769
"publisher": "Sebastian Mayr",
792770
"email": "[email protected]",
793-
"path": "node_modules/jsdom/node_modules/whatwg-url",
794-
"licenseFile": "node_modules/jsdom/node_modules/whatwg-url/LICENSE.txt"
771+
"path": "node_modules/whatwg-url",
772+
"licenseFile": "node_modules/whatwg-url/LICENSE.txt"
795773
},
796774
797775
"licenses": "MIT",
798776
"repository": "https://github.com/jsdom/whatwg-url",
799777
"publisher": "Sebastian Mayr",
800778
"email": "[email protected]",
801-
"path": "node_modules/whatwg-url",
802-
"licenseFile": "node_modules/whatwg-url/LICENSE.txt"
779+
"path": "node_modules/data-urls/node_modules/whatwg-url",
780+
"licenseFile": "node_modules/data-urls/node_modules/whatwg-url/LICENSE.txt"
803781
},
804782
805783
"licenses": "MIT",

yarn.lock

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1648,13 +1648,6 @@ __metadata:
16481648
languageName: node
16491649
linkType: hard
16501650

1651-
"@types/trusted-types@npm:^2.0.7":
1652-
version: 2.0.7
1653-
resolution: "@types/trusted-types@npm:2.0.7"
1654-
checksum: 10c0/4c4855f10de7c6c135e0d32ce462419d8abbbc33713b31d294596c0cc34ae1fa6112a2f9da729c8f7a20707782b0d69da3b1f8df6645b0366d08825ca1522e0c
1655-
languageName: node
1656-
linkType: hard
1657-
16581651
"@typescript-eslint/eslint-plugin@npm:^5.60.1":
16591652
version: 5.62.0
16601653
resolution: "@typescript-eslint/eslint-plugin@npm:5.62.0"
@@ -2011,7 +2004,6 @@ __metadata:
20112004
cross-env: "npm:^7.0.2"
20122005
d3: "npm:^7.0.0"
20132006
diff: "npm:^5.0.0"
2014-
dompurify: "npm:^3.2.5"
20152007
dprint: "npm:^0.47.2"
20162008
esbuild: "npm:^0.19.10"
20172009
esbuild-sass-plugin: "npm:^2"
@@ -3162,18 +3154,6 @@ __metadata:
31623154
languageName: node
31633155
linkType: hard
31643156

3165-
"dompurify@npm:^3.2.5":
3166-
version: 3.2.5
3167-
resolution: "dompurify@npm:3.2.5"
3168-
dependencies:
3169-
"@types/trusted-types": "npm:^2.0.7"
3170-
dependenciesMeta:
3171-
"@types/trusted-types":
3172-
optional: true
3173-
checksum: 10c0/b564167cc588933ad2d25c185296716bdd7124e9d2a75dac76efea831bb22d1230ce5205a1ab6ce4c1010bb32ac35f7a5cb2dd16c78cbf382111f1228362aa59
3174-
languageName: node
3175-
linkType: hard
3176-
31773157
"domutils@npm:^3.0.1":
31783158
version: 3.1.0
31793159
resolution: "domutils@npm:3.1.0"

0 commit comments

Comments
 (0)