Skip to content

Commit

Permalink
no strict csp (#4571)
Browse files Browse the repository at this point in the history
  • Loading branch information
mei23 authored Mar 14, 2023
1 parent 58ce960 commit a80111e
Show file tree
Hide file tree
Showing 7 changed files with 26 additions and 35 deletions.
5 changes: 2 additions & 3 deletions src/server/web/docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,18 +92,17 @@ router.get('/*/*', async ctx => {
});
const md = await fs.promises.readFile(`${__dirname}/../../docs/${doc}.${lang}.md`, 'utf8');

const { csp, nonce } = genCsp();
const { csp } = genCsp();

await ctx.render('docs-article', Object.assign({
id: doc,
html: conv.makeHtml(md),
title: md.match(/^# (.+?)\r?\n/)[1],
version: config.version,
nonce,
}, await genVars(lang)));

ctx.set('Content-Security-Policy', csp);
ctx.set('Cache-Control', 'private, no-store, no-cache, must-revalidate');
ctx.set('Cache-Control', 'public, max-age=60');
});

export default router;
46 changes: 19 additions & 27 deletions src/server/web/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,16 @@ import { getJSONFeed } from './feed/json';
import { buildMeta } from '../../misc/build-meta';
import Page, { packPage } from '../../models/page';
import { fromHtml } from '../../mfm/from-html';
import * as crypto from 'crypto';
const htmlescape = require('htmlescape');

const staticAssets = `${__dirname}/../../../assets/`;
const client = `${__dirname}/../../client/`;

export function genCsp() {
const nonce = crypto.randomBytes(16).toString('base64');

const csp
= `base-uri 'none'; `
+ `default-src 'none'; `
+ `script-src 'nonce-${nonce}' 'strict-dynamic' https:; ` // CSP3対応ブラウザはhttps:を無視する
+ `script-src 'self' https://www.recaptcha.net/recaptcha/ https://www.gstatic.com/recaptcha/; `
+ `img-src 'self' https: data: blob:; `
+ `media-src 'self' https:; `
+ `style-src 'self' 'unsafe-inline'; `
Expand All @@ -47,7 +44,7 @@ export function genCsp() {
+ `connect-src 'self' data: blob: ${config.wsUrl} https://api.rss2json.com; ` // wssを指定しないとSafariで動かない https://github.com/w3c/webappsec-csp/issues/7#issuecomment-1086257826
+ `frame-ancestors 'none'`;

return { csp, nonce };
return { csp };
}

// Init app
Expand Down Expand Up @@ -126,15 +123,14 @@ router.get('/robots.txt', async ctx => {
// Docs
router.use('/docs', docs.routes());
router.get('/api-doc', async ctx => {
const { csp, nonce } = genCsp();
const { csp } = genCsp();

await ctx.render('redoc', {
version: config.version,
nonce,
});

ctx.set('Content-Security-Policy', csp);
ctx.set('Cache-Control', 'private, no-store, no-cache, must-revalidate');
ctx.set('Cache-Control', 'public, max-age=60');
});

// URL preview endpoint
Expand Down Expand Up @@ -206,11 +202,10 @@ router.get(['/@:user', '/@:user/:sub'], async (ctx, next) => {
.map(field => field.value)
: [];

const { csp, nonce } = genCsp();
const { csp } = genCsp();

await ctx.render('user', {
version: config.version,
nonce,
initialMeta: htmlescape(builded),
user,
me,
Expand All @@ -223,7 +218,7 @@ router.get(['/@:user', '/@:user/:sub'], async (ctx, next) => {
});

ctx.set('Content-Security-Policy', csp);
ctx.set('Cache-Control', 'private, no-store, no-cache, must-revalidate');
ctx.set('Cache-Control', 'public, max-age=60');
}
});

Expand Down Expand Up @@ -304,11 +299,10 @@ router.get('/notes/:note', async (ctx, next) => {
const width = 530; // TODO: thumbnail width
const height = 255;

const { csp, nonce } = genCsp();
const { csp } = genCsp();

await ctx.render('note', {
version: config.version,
nonce,
initialMeta: htmlescape(builded),
note: _note,
summary: getNoteSummary(_note),
Expand All @@ -322,7 +316,7 @@ router.get('/notes/:note', async (ctx, next) => {
});

ctx.set('Content-Security-Policy', csp);
ctx.set('Cache-Control', 'private, no-store, no-cache, must-revalidate');
ctx.set('Cache-Control', 'public, max-age=60');

return;
});
Expand All @@ -344,7 +338,7 @@ router.get('/notes/:note/embed', async ctx => {
.filter((file: any) => file.type.match(/^audio/) && !file.isSensitive)
.shift();

const { csp, nonce } = genCsp();
const { csp } = genCsp();

await ctx.render('note-embed', {
video: video?.url,
Expand Down Expand Up @@ -389,10 +383,9 @@ router.get('/@:user/pages/:page', async ctx => {
const _page = await packPage(page, user._id);
const meta = await fetchMeta();
const builded = await buildMeta(meta, false);
const { csp, nonce } = genCsp();
const { csp } = genCsp();
await ctx.render('page', {
version: config.version,
nonce,
initialMeta: htmlescape(builded),
page: _page,
instanceName: meta.name || 'Misskey',
Expand All @@ -402,7 +395,11 @@ router.get('/@:user/pages/:page', async ctx => {
});

ctx.set('Content-Security-Policy', csp);
ctx.set('Cache-Control', 'private, no-store, no-cache, must-revalidate');
if (['public'].includes(page.visibility)) {
ctx.set('Cache-Control', 'public, max-age=60');
} else {
ctx.set('Cache-Control', 'private, max-age=0, must-revalidate');
}

return;
}
Expand All @@ -421,16 +418,14 @@ router.get('/info', async ctx => {
_id: false
}
});
const { csp, nonce } = genCsp();
const { csp } = genCsp();
await ctx.render('info', {
version: config.version,
nonce,
emojis: emojis,
meta: meta,
desc,
});
ctx.set('Content-Security-Policy', csp);
ctx.set('Cache-Control', 'private, no-store, no-cache, must-revalidate');
});

const override = (source: string, target: string, depth: number = 0) =>
Expand All @@ -440,15 +435,13 @@ router.get('/othello', async ctx => ctx.redirect(override(ctx.URL.pathname, 'gam
router.get('/reversi', async ctx => ctx.redirect(override(ctx.URL.pathname, 'games')));

router.get('/flush', async ctx => {
const { csp, nonce } = genCsp();
const { csp } = genCsp();

await ctx.render('flush', {
version: config.version,
nonce,
});

ctx.set('Content-Security-Policy', csp);
ctx.set('Cache-Control', 'private, no-store, no-cache, must-revalidate');
});

// streamingに非WebSocketリクエストが来た場合にbase htmlをキャシュ付きで返すと、Proxy等でそのパスがキャッシュされておかしくなる
Expand Down Expand Up @@ -481,11 +474,10 @@ router.get('*', async ctx => {

const noindex = ctx.path.match(/^[/](search|tags[/]|explore|featured)/);

const { csp, nonce } = genCsp();
const { csp } = genCsp();

await ctx.render('base', {
version: config.version,
nonce,
initialMeta: htmlescape(builded),
img: meta.bannerUrl,
title: meta.name || 'Misskey',
Expand All @@ -498,7 +490,7 @@ router.get('*', async ctx => {
});

ctx.set('Content-Security-Policy', csp);
ctx.set('Cache-Control', 'private, no-store, no-cache, must-revalidate');
ctx.set('Cache-Control', 'public, max-age=60');
});

// Register router
Expand Down
2 changes: 1 addition & 1 deletion src/server/web/views/base.pug
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ html
style
include ./../../../../built/client/assets/init.css

script(src=`/assets/boot.js?${version}` nonce=nonce)
script(src=`/assets/boot.js?${version}`)

script(type='application/json' id='initial-meta').
!{initialMeta}
Expand Down
2 changes: 1 addition & 1 deletion src/server/web/views/docs-base.pug
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ html(lang= lang)
| #{title} | Misskey Docs
link(rel="stylesheet" href=`/docs/assets/style.css?${version}`)
link(rel="stylesheet" href="/assets/monokai-sublime.min.css?10.6.0" integrity="sha512-/l4iViNMhxR5MhSlak3Yw/L/7qUBifVy7MpLjeJTc8BPMRFbGplGN0xqufCDwhSdxSnVgy+e/OYsNnU75K3yyQ==")
script(src="/assets/highlight.min.js?10.6.0" integrity="sha512-zol3kFQ5tnYhL7PzGt0LnllHHVWRGt2bTCIywDiScVvLIlaDOVJ6sPdJTVi0m3rA660RT+yZxkkRzMbb1L8Zkw==" nonce=nonce)
script(src="/assets/highlight.min.js?10.6.0" integrity="sha512-zol3kFQ5tnYhL7PzGt0LnllHHVWRGt2bTCIywDiScVvLIlaDOVJ6sPdJTVi0m3rA660RT+yZxkkRzMbb1L8Zkw==")
block meta

body
Expand Down
2 changes: 1 addition & 1 deletion src/server/web/views/flush.pug
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ doctype html

html
#msg
script(src=`/assets/flush.js?${version}` nonce=nonce)
script(src=`/assets/flush.js?${version}`)

2 changes: 1 addition & 1 deletion src/server/web/views/redoc.pug
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ head
padding: 0;
}
redoc(spec-url='/api.json' expand-responses='200' expand-single-schema-field='true')
script(src='/assets/redoc.standalone.js?2.0.0-rc.50' integrity='sha256-WJbngBWN9vp6vkEuzeoSj5tE5saW9Hfj6/SinkzhL2s=' nonce=nonce)
script(src='/assets/redoc.standalone.js?2.0.0-rc.50' integrity='sha256-WJbngBWN9vp6vkEuzeoSj5tE5saW9Hfj6/SinkzhL2s=')
2 changes: 1 addition & 1 deletion test/fetch-resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const AP = 'application/activity+json; charset=utf-8';
const JSON = 'application/json; charset=utf-8';
const HTML = 'text/html; charset=utf-8';

const CSP_STRICT = `base-uri 'none'; default-src 'none'; script-src 'nonce-X 'strict-dynamic' https:; img-src 'self' https: data: blob:; media-src 'self' https:; style-src 'self' 'unsafe-inline'; font-src 'self'; frame-src 'self' https:; manifest-src 'self'; connect-src 'self' data: blob: ws://misskey.local https://api.rss2json.com; frame-ancestors 'none'`;
const CSP_STRICT = `base-uri 'none'; default-src 'none'; script-src 'self' https://www.recaptcha.net/recaptcha/ https://www.gstatic.com/recaptcha/; img-src 'self' https: data: blob:; media-src 'self' https:; style-src 'self' 'unsafe-inline'; font-src 'self'; frame-src 'self' https:; manifest-src 'self'; connect-src 'self' data: blob: ws://misskey.local https://api.rss2json.com; frame-ancestors 'none'`;

describe('Fetch resource', () => {
let p: childProcess.ChildProcess;
Expand Down

0 comments on commit a80111e

Please sign in to comment.