mirror of
https://github.com/directus/directus.git
synced 2026-04-25 03:00:53 -04:00
Use json parser wrapper function to prevent pollution attacks (#13191)
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
import { SchemaOverview } from '@directus/schema/dist/types/overview';
|
||||
import { Column } from 'knex-schema-inspector/dist/types/column';
|
||||
import getLocalType from './get-local-type';
|
||||
import logger from '../logger';
|
||||
import env from '../env';
|
||||
import logger from '../logger';
|
||||
import getLocalType from './get-local-type';
|
||||
import { parseJSON } from './parse-json';
|
||||
|
||||
export default function getDefaultValue(
|
||||
column: SchemaOverview[string]['columns'][string] | Column
|
||||
@@ -59,7 +60,7 @@ function castToObject(value: any): any | any[] {
|
||||
|
||||
if (typeof value === 'string') {
|
||||
try {
|
||||
return JSON.parse(value);
|
||||
return parseJSON(value);
|
||||
} catch (err: any) {
|
||||
if (env.NODE_ENV === 'development') {
|
||||
logger.error(err);
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import { Permission, Accountability, SchemaOverview } from '@directus/shared/types';
|
||||
import { Accountability, Permission, SchemaOverview } from '@directus/shared/types';
|
||||
import { deepMap, parseFilter, parsePreset } from '@directus/shared/utils';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import hash from 'object-hash';
|
||||
import { getCache, setSystemCache } from '../cache';
|
||||
import getDatabase from '../database';
|
||||
import { appAccessMinimalPermissions } from '../database/system-data/app-access-permissions';
|
||||
import env from '../env';
|
||||
import { RolesService } from '../services/roles';
|
||||
import { UsersService } from '../services/users';
|
||||
import { mergePermissions } from '../utils/merge-permissions';
|
||||
import { mergePermissionsForShare } from './merge-permissions-for-share';
|
||||
import { UsersService } from '../services/users';
|
||||
import { RolesService } from '../services/roles';
|
||||
import { getCache, setSystemCache } from '../cache';
|
||||
import hash from 'object-hash';
|
||||
import env from '../env';
|
||||
import { parseJSON } from './parse-json';
|
||||
|
||||
export async function getPermissions(accountability: Accountability, schema: SchemaOverview) {
|
||||
const database = getDatabase();
|
||||
@@ -117,19 +118,19 @@ function parsePermissions(permissions: any[]) {
|
||||
const permission = cloneDeep(permissionRaw);
|
||||
|
||||
if (permission.permissions && typeof permission.permissions === 'string') {
|
||||
permission.permissions = JSON.parse(permission.permissions);
|
||||
permission.permissions = parseJSON(permission.permissions);
|
||||
} else if (permission.permissions === null) {
|
||||
permission.permissions = {};
|
||||
}
|
||||
|
||||
if (permission.validation && typeof permission.validation === 'string') {
|
||||
permission.validation = JSON.parse(permission.validation);
|
||||
permission.validation = parseJSON(permission.validation);
|
||||
} else if (permission.validation === null) {
|
||||
permission.validation = {};
|
||||
}
|
||||
|
||||
if (permission.presets && typeof permission.presets === 'string') {
|
||||
permission.presets = JSON.parse(permission.presets);
|
||||
permission.presets = parseJSON(permission.presets);
|
||||
} else if (permission.presets === null) {
|
||||
permission.presets = {};
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import logger from '../logger';
|
||||
import { RelationsService } from '../services';
|
||||
import getDefaultValue from './get-default-value';
|
||||
import getLocalType from './get-local-type';
|
||||
import { parseJSON } from './parse-json';
|
||||
|
||||
export async function getSchema(options?: {
|
||||
accountability?: Accountability;
|
||||
@@ -142,7 +143,7 @@ async function getDatabaseSchema(
|
||||
const type = (existing && getLocalType(column, { special })) || 'alias';
|
||||
let validation = field.validation ?? null;
|
||||
|
||||
if (validation && typeof validation === 'string') validation = JSON.parse(validation);
|
||||
if (validation && typeof validation === 'string') validation = parseJSON(validation);
|
||||
|
||||
result.collections[field.collection].fields[field.field] = {
|
||||
field: field.field,
|
||||
|
||||
16
api/src/utils/parse-json.ts
Normal file
16
api/src/utils/parse-json.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Run JSON.parse, but ignore `__proto__` properties. This prevents prototype pollution attacks
|
||||
*/
|
||||
export function parseJSON(input: string): any {
|
||||
if (String(input).includes('__proto__')) {
|
||||
return JSON.parse(input, noproto);
|
||||
}
|
||||
|
||||
return JSON.parse(input);
|
||||
}
|
||||
|
||||
export function noproto<T>(key: string, value: T): T | void {
|
||||
if (key !== '__proto__') {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Accountability, Aggregate, Filter, Query } from '@directus/shared/types';
|
||||
import { parseFilter } from '@directus/shared/utils';
|
||||
import { flatten, get, isPlainObject, merge, set } from 'lodash';
|
||||
import logger from '../logger';
|
||||
import { Meta } from '../types';
|
||||
import { Query, Aggregate, Filter } from '@directus/shared/types';
|
||||
import { Accountability } from '@directus/shared/types';
|
||||
import { parseFilter } from '@directus/shared/utils';
|
||||
import { parseJSON } from './parse-json';
|
||||
|
||||
export function sanitizeQuery(rawQuery: Record<string, any>, accountability?: Accountability | null): Query {
|
||||
const query: Query = {};
|
||||
@@ -99,7 +99,7 @@ function sanitizeAggregate(rawAggregate: any): Aggregate {
|
||||
|
||||
if (typeof rawAggregate === 'string') {
|
||||
try {
|
||||
aggregate = JSON.parse(rawAggregate);
|
||||
aggregate = parseJSON(rawAggregate);
|
||||
} catch {
|
||||
logger.warn('Invalid value passed for filter query parameter.');
|
||||
}
|
||||
@@ -118,7 +118,7 @@ function sanitizeFilter(rawFilter: any, accountability: Accountability | null) {
|
||||
|
||||
if (typeof rawFilter === 'string') {
|
||||
try {
|
||||
filters = JSON.parse(rawFilter);
|
||||
filters = parseJSON(rawFilter);
|
||||
} catch {
|
||||
logger.warn('Invalid value passed for filter query parameter.');
|
||||
}
|
||||
@@ -161,7 +161,7 @@ function sanitizeDeep(deep: Record<string, any>, accountability?: Accountability
|
||||
|
||||
if (typeof deep === 'string') {
|
||||
try {
|
||||
deep = JSON.parse(deep);
|
||||
deep = parseJSON(deep);
|
||||
} catch {
|
||||
logger.warn('Invalid value passed for deep query parameter.');
|
||||
}
|
||||
@@ -200,7 +200,7 @@ function sanitizeAlias(rawAlias: any) {
|
||||
|
||||
if (typeof rawAlias === 'string') {
|
||||
try {
|
||||
alias = JSON.parse(rawAlias);
|
||||
alias = parseJSON(rawAlias);
|
||||
} catch (err) {
|
||||
logger.warn('Invalid value passed for alias query parameter.');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user