Merge branch 'develop' into sec/updateMySQL2

This commit is contained in:
Alexandre BODIN 2024-06-03 10:40:03 +02:00 committed by GitHub
commit 94739c5a56
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 76 additions and 6 deletions

View File

@ -295,7 +295,6 @@ jobs:
MYSQL_USER: strapi
MYSQL_PASSWORD: strapi
MYSQL_DATABASE: strapi_test
MYSQL_AUTHENTICATION_PLUGIN: mysql_native_password
options: >-
--health-cmd="mysqladmin ping"
--health-interval=10s
@ -450,7 +449,6 @@ jobs:
MYSQL_USER: strapi
MYSQL_PASSWORD: strapi
MYSQL_DATABASE: strapi_test
MYSQL_AUTHENTICATION_PLUGIN: mysql_native_password
options: >-
--health-cmd="mysqladmin ping"
--health-interval=10s

View File

@ -16,7 +16,6 @@ services:
mysql:
image: mysql
restart: always
command: --default-authentication-plugin=mysql_native_password
environment:
MYSQL_DATABASE: strapi_test
MYSQL_USER: strapi

View File

@ -0,0 +1,65 @@
import Koa from 'koa';
import request from 'supertest';
import { security } from '../security';
const parseCspHeader = (csp: string) =>
Object.fromEntries(
csp
.split(';')
.map((directive) => directive.split(' '))
.map(([k, ...v]) => [k, v])
);
describe('Security middleware', () => {
describe('Content security policy', () => {
// GIVEN
const app = new Koa();
const securityMiddleware = security(
{
contentSecurityPolicy: {
useDefaults: true,
directives: {
'script-src': ["'self'", 'https://cdn.custom.com'],
upgradeInsecureRequests: null,
},
},
},
{
strapi: {
plugin: () => null,
} as any,
}
)!;
// WHEN
app.use(securityMiddleware);
const agent = request.agent(app.callback());
// THEN
it.each(['/', '/admin', '/api'])(
'includes user custom CSP directives in GET %s response',
async (path) => {
await agent.get(path).expect((req) => {
const csp = parseCspHeader(req.header['content-security-policy']);
expect(csp['script-src']).toContain('https://cdn.custom.com');
});
}
);
it('includes required default CSP directives in GET /admin response', async () => {
await agent.get('/admin').expect((req) => {
const csp = parseCspHeader(req.header['content-security-policy']);
expect(csp['script-src']).toContain("'unsafe-inline'");
expect(csp['connect-src']).toContain('ws:');
});
});
it('includes required default CSP directives in GET /documentation response', async () => {
await agent.get('/documentation').expect((req) => {
const csp = parseCspHeader(req.header['content-security-policy']);
expect(csp['script-src']).toContain("'unsafe-inline'");
expect(csp['script-src']).toContain('cdn.jsdelivr.net');
expect(csp['img-src']).toContain('strapi.io');
expect(csp['img-src']).toContain('cdn.jsdelivr.net');
});
});
});
});

View File

@ -1,4 +1,4 @@
import { defaultsDeep, merge } from 'lodash/fp';
import { defaultsDeep, mergeWith } from 'lodash/fp';
import helmet, { KoaHelmet } from 'koa-helmet';
import type { Common } from '@strapi/types';
@ -29,6 +29,14 @@ const defaults: Config = {
},
};
const mergeConfig = (existingConfig: Config, newConfig: Config) => {
return mergeWith(
(obj, src) => (Array.isArray(obj) && Array.isArray(src) ? obj.concat(src) : undefined),
existingConfig,
newConfig
);
};
export const security: Common.MiddlewareFactory<Config> =
(config, { strapi }) =>
(ctx, next) => {
@ -42,7 +50,7 @@ export const security: Common.MiddlewareFactory<Config> =
}
if (ctx.method === 'GET' && specialPaths.some((str) => ctx.path.startsWith(str))) {
helmetConfig = merge(helmetConfig, {
helmetConfig = mergeConfig(helmetConfig, {
contentSecurityPolicy: {
directives: {
'script-src': ["'self'", "'unsafe-inline'", 'cdn.jsdelivr.net'],
@ -53,7 +61,7 @@ export const security: Common.MiddlewareFactory<Config> =
}
if (ctx.method === 'GET' && ['/admin'].some((str) => ctx.path.startsWith(str))) {
helmetConfig = merge(helmetConfig, {
helmetConfig = mergeConfig(helmetConfig, {
contentSecurityPolicy: {
directives: {
'script-src': ["'self'", "'unsafe-inline'"],