improve security against injection (#2669)
* improve security against injection * fix shell injection through ipv4, ipv6 address Co-authored-by: 7megaumka7 <116706490+7megaumka7@users.noreply.github.com> --------- Co-authored-by: 7megaumka7 <116706490+7megaumka7@users.noreply.github.com>
This commit is contained in:
co-authored by
7megaumka7
parent
5f54fa3e58
commit
032347648d
@@ -204,7 +204,9 @@
|
|||||||
"validBoolean": "{0} must be a valid boolean",
|
"validBoolean": "{0} must be a valid boolean",
|
||||||
"validArray": "{0} must be a valid array",
|
"validArray": "{0} must be a valid array",
|
||||||
"stringMin": "{0} must be at least {1} Character",
|
"stringMin": "{0} must be at least {1} Character",
|
||||||
"numberMin": "{0} must be at least {1}"
|
"stringMax": "{0} must be at most {1} Character",
|
||||||
|
"numberMin": "{0} must be at least {1}",
|
||||||
|
"numberMax": "{0} must be at most {1}"
|
||||||
},
|
},
|
||||||
"client": {
|
"client": {
|
||||||
"id": "Client ID",
|
"id": "Client ID",
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
import { z } from 'zod';
|
import { Verify2faSchema } from '#db/repositories/user/types';
|
||||||
|
|
||||||
const Verify2faSchema = z.object({
|
|
||||||
totpCode: z.string().min(6).max(6),
|
|
||||||
});
|
|
||||||
|
|
||||||
export default defineEventHandler(async (event) => {
|
export default defineEventHandler(async (event) => {
|
||||||
const { totpCode } = await readValidatedBody(
|
const { totpCode } = await readValidatedBody(
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import type { InferSelectModel } from 'drizzle-orm';
|
import type { InferSelectModel } from 'drizzle-orm';
|
||||||
import z from 'zod';
|
import z from 'zod';
|
||||||
|
|
||||||
|
import { isIPv4, isIPv6 } from 'is-ip';
|
||||||
import type { client } from './schema';
|
import type { client } from './schema';
|
||||||
|
|
||||||
export type ClientType = InferSelectModel<typeof client>;
|
export type ClientType = InferSelectModel<typeof client>;
|
||||||
@@ -20,7 +21,8 @@ export type UpdateClientType = Omit<
|
|||||||
const name = z
|
const name = z
|
||||||
.string({ message: t('zod.client.name') })
|
.string({ message: t('zod.client.name') })
|
||||||
.min(1, t('zod.client.name'))
|
.min(1, t('zod.client.name'))
|
||||||
.pipe(safeStringRefine);
|
.pipe(safeStringRefine)
|
||||||
|
.pipe(controlStringRefine);
|
||||||
|
|
||||||
// TODO?: validate iso string
|
// TODO?: validate iso string
|
||||||
const expiresAt = z
|
const expiresAt = z
|
||||||
@@ -32,14 +34,18 @@ const expiresAt = z
|
|||||||
const address4 = z
|
const address4 = z
|
||||||
.string({ message: t('zod.client.address4') })
|
.string({ message: t('zod.client.address4') })
|
||||||
.min(1, { message: t('zod.client.address4') })
|
.min(1, { message: t('zod.client.address4') })
|
||||||
.pipe(safeStringRefine);
|
.pipe(safeStringRefine)
|
||||||
|
.pipe(controlStringRefine)
|
||||||
|
.refine((v) => isIPv4(v));
|
||||||
|
|
||||||
const address6 = z
|
const address6 = z
|
||||||
.string({ message: t('zod.client.address6') })
|
.string({ message: t('zod.client.address6') })
|
||||||
.min(1, { message: t('zod.client.address6') })
|
.min(1, { message: t('zod.client.address6') })
|
||||||
.pipe(safeStringRefine);
|
.pipe(safeStringRefine)
|
||||||
|
.pipe(controlStringRefine)
|
||||||
|
.refine((v) => isIPv6(v));
|
||||||
|
|
||||||
const filter = z.string().optional();
|
const filter = z.string().pipe(safeStringRefine).optional();
|
||||||
|
|
||||||
const serverAllowedIps = z.array(AddressSchema, {
|
const serverAllowedIps = z.array(AddressSchema, {
|
||||||
message: t('zod.client.serverAllowedIps'),
|
message: t('zod.client.serverAllowedIps'),
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ const metricsEnabled = z.boolean({ message: t('zod.general.metricsEnabled') });
|
|||||||
const metricsPassword = z
|
const metricsPassword = z
|
||||||
.string({ message: t('zod.general.metricsPassword') })
|
.string({ message: t('zod.general.metricsPassword') })
|
||||||
.min(1, { message: t('zod.general.metricsPassword') })
|
.min(1, { message: t('zod.general.metricsPassword') })
|
||||||
|
.pipe(safeStringRefine)
|
||||||
.nullable();
|
.nullable();
|
||||||
|
|
||||||
export const GeneralUpdateSchema = z.object({
|
export const GeneralUpdateSchema = z.object({
|
||||||
|
|||||||
@@ -46,9 +46,8 @@ const name = z
|
|||||||
.pipe(safeStringRefine);
|
.pipe(safeStringRefine);
|
||||||
|
|
||||||
const email = z
|
const email = z
|
||||||
.string({ message: t('zod.user.email') })
|
|
||||||
.min(5, t('zod.user.email'))
|
|
||||||
.email({ message: t('zod.user.emailInvalid') })
|
.email({ message: t('zod.user.emailInvalid') })
|
||||||
|
.min(5, t('zod.user.email'))
|
||||||
.pipe(safeStringRefine)
|
.pipe(safeStringRefine)
|
||||||
.nullable();
|
.nullable();
|
||||||
|
|
||||||
@@ -80,3 +79,7 @@ export const UserUpdateTotpSchema = z.union([
|
|||||||
currentPassword: password,
|
currentPassword: password,
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
export const Verify2faSchema = z.object({
|
||||||
|
totpCode: totpCode,
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { ZodSchema } from 'zod';
|
import type { ZodType } from 'zod';
|
||||||
import z from 'zod';
|
import z from 'zod';
|
||||||
import type { H3Event, EventHandlerRequest } from 'h3';
|
import type { H3Event, EventHandlerRequest } from 'h3';
|
||||||
import { isIP } from 'is-ip';
|
import { isIP } from 'is-ip';
|
||||||
@@ -20,6 +20,15 @@ export const safeStringRefine = z
|
|||||||
{ message: t('zod.stringMalformed') }
|
{ message: t('zod.stringMalformed') }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
function hasControlChars(str: string) {
|
||||||
|
// eslint-disable-next-line no-control-regex
|
||||||
|
return /[\x00-\x1F\x7F]/.test(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const controlStringRefine = z
|
||||||
|
.string()
|
||||||
|
.refine((v) => !hasControlChars(v), { message: t('zod.stringMalformed') });
|
||||||
|
|
||||||
export const EnabledSchema = z.boolean({ message: t('zod.enabled') });
|
export const EnabledSchema = z.boolean({ message: t('zod.enabled') });
|
||||||
|
|
||||||
export const MtuSchema = z
|
export const MtuSchema = z
|
||||||
@@ -70,7 +79,11 @@ export const HSchema = z
|
|||||||
})
|
})
|
||||||
.nullable();
|
.nullable();
|
||||||
|
|
||||||
export const ISchema = z.string().nullable();
|
export const ISchema = z
|
||||||
|
.string()
|
||||||
|
.pipe(safeStringRefine)
|
||||||
|
.pipe(controlStringRefine)
|
||||||
|
.nullable();
|
||||||
|
|
||||||
export const PortSchema = z
|
export const PortSchema = z
|
||||||
.number({ message: t('zod.port') })
|
.number({ message: t('zod.port') })
|
||||||
@@ -85,7 +98,8 @@ export const PersistentKeepaliveSchema = z
|
|||||||
export const AddressSchema = z
|
export const AddressSchema = z
|
||||||
.string({ message: t('zod.address') })
|
.string({ message: t('zod.address') })
|
||||||
.min(1, { message: t('zod.address') })
|
.min(1, { message: t('zod.address') })
|
||||||
.pipe(safeStringRefine);
|
.pipe(safeStringRefine)
|
||||||
|
.pipe(controlStringRefine);
|
||||||
|
|
||||||
export const DnsSchema = z.array(AddressSchema, { message: t('zod.dns') });
|
export const DnsSchema = z.array(AddressSchema, { message: t('zod.dns') });
|
||||||
|
|
||||||
@@ -168,7 +182,7 @@ export const schemaForType =
|
|||||||
};
|
};
|
||||||
|
|
||||||
export function validateZod<T>(
|
export function validateZod<T>(
|
||||||
schema: ZodSchema<T>,
|
schema: ZodType<T>,
|
||||||
event: H3Event<EventHandlerRequest>
|
event: H3Event<EventHandlerRequest>
|
||||||
) {
|
) {
|
||||||
return async (data: unknown) => {
|
return async (data: unknown) => {
|
||||||
@@ -203,6 +217,22 @@ export function validateZod<T>(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'too_big':
|
||||||
|
switch (v.origin) {
|
||||||
|
case 'string':
|
||||||
|
newMessage = t('zod.generic.stringMax', [
|
||||||
|
t(v.message),
|
||||||
|
v.maximum,
|
||||||
|
]);
|
||||||
|
break;
|
||||||
|
case 'number':
|
||||||
|
newMessage = t('zod.generic.numberMax', [
|
||||||
|
t(v.message),
|
||||||
|
v.maximum,
|
||||||
|
]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'invalid_type': {
|
case 'invalid_type': {
|
||||||
if (v.input === null || v.input === undefined) {
|
if (v.input === null || v.input === undefined) {
|
||||||
newMessage = t('zod.generic.required', [
|
newMessage = t('zod.generic.required', [
|
||||||
|
|||||||
Reference in New Issue
Block a user