Skip to content

Commit

Permalink
f
Browse files Browse the repository at this point in the history
  • Loading branch information
fengmk2 committed Jan 16, 2025
1 parent b3e0828 commit 7b357c1
Show file tree
Hide file tree
Showing 9 changed files with 155 additions and 80 deletions.
65 changes: 65 additions & 0 deletions __snapshots__/csrf.test.ts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
exports['test/csrf.test.ts should update form with csrf token 1'] = {
"ignore": [
{},
null
],
"enable": true,
"type": "ctoken",
"ignoreJSON": false,
"cookieName": "csrfToken",
"sessionName": "csrfToken",
"headerName": "x-csrf-token",
"bodyName": "_csrf",
"queryName": "_csrf",
"rotateWhenInvalid": false,
"useSession": false,
"supportedRequests": [
{
"path": {},
"methods": [
"POST",
"PATCH",
"DELETE",
"PUT",
"CONNECT"
]
}
],
"refererWhiteList": [],
"cookieOptions": {
"signed": false,
"httpOnly": false,
"overwrite": true
}
}

exports['test/csrf.test.ts apps/csrf-supported-requests-default-config should works without error because csrf = false override default config 1'] = {
"enable": false,
"type": "ctoken",
"ignoreJSON": false,
"cookieName": "csrfToken",
"sessionName": "csrfToken",
"headerName": "x-csrf-token",
"bodyName": "_csrf",
"queryName": "_csrf",
"rotateWhenInvalid": false,
"useSession": false,
"supportedRequests": [
{
"path": {},
"methods": [
"POST",
"PATCH",
"DELETE",
"PUT",
"CONNECT"
]
}
],
"refererWhiteList": [],
"cookieOptions": {
"signed": false,
"httpOnly": false,
"overwrite": true
}
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"@arethetypeswrong/cli": "^0.17.1",
"@eggjs/bin": "7",
"@eggjs/mock": "^6.0.5",
"@eggjs/supertest": "^8.1.1",
"@eggjs/tsconfig": "1",
"@types/escape-html": "^1.0.4",
"@types/extend": "^3.0.4",
Expand Down
17 changes: 8 additions & 9 deletions src/app.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import assert from 'node:assert';
import type { ILifecycleBoot, EggCore } from '@eggjs/core';
import { preprocessConfig } from './lib/utils.js';
import { SecurityConfig } from './config/config.default.js';
Expand All @@ -10,23 +9,23 @@ export default class AgentBoot implements ILifecycleBoot {
this.app = app;
}

async configWillLoad() {
configWillLoad() {
const app = this.app;
app.config.coreMiddleware.push('securities');
// parse config and check if config is legal
app.config.security = SecurityConfig.parse(app.config.security);

if (app.config.security.csrf && app.config.security.csrf.enable) {
const { ignoreJSON, type } = app.config.security.csrf;
if (app.config.security.csrf.enable) {
const { ignoreJSON } = app.config.security.csrf;
if (ignoreJSON) {
app.deprecate('[@eggjs/security/app] `app.config.security.csrf.ignoreJSON` is not safe now, please disable it.');
}

const legalTypes = [ 'all', 'referer', 'ctoken', 'any' ];
assert(legalTypes.includes(type),
'[@eggjs/security/ap] `config.security.csrf.type` must be one of ' + legalTypes.join(', '));
// const legalTypes = [ 'all', 'referer', 'ctoken', 'any' ];
// assert(legalTypes.includes(type),
// '[@eggjs/security/ap] `config.security.csrf.type` must be one of ' + legalTypes.join(', '));
}

// parse config and check if config is legal
app.config.security = SecurityConfig.parse(app.config.security);
preprocessConfig(app.config.security);
}
}
12 changes: 9 additions & 3 deletions src/config/config.default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export type SecurityMiddlewareName = z.infer<typeof SecurityMiddlewareName>;
/**
* (ctx) => boolean
*/
const IgnoreOrMatchHandler = z.function().args(z.string()).returns(z.boolean());
const IgnoreOrMatchHandler = z.function().args(z.any()).returns(z.boolean());
export type IgnoreOrMatchHandler = z.infer<typeof IgnoreOrMatchHandler>;

const IgnoreOrMatch = z.union([
Expand Down Expand Up @@ -76,7 +76,13 @@ export const SecurityConfig = z.object({
/**
* whether defend csrf attack
*/
csrf: z.object({
csrf: z.preprocess(val => {
// transform old config, `csrf: false` to `csrf: { enable: false }`
if (typeof val === 'boolean') {
return { enable: val };
}
return val;
}, z.object({
match: IgnoreOrMatchOption,
ignore: IgnoreOrMatchOption,
/**
Expand Down Expand Up @@ -183,7 +189,7 @@ export const SecurityConfig = z.object({
httpOnly: false,
overwrite: true,
}),
}).default({}),
}).default({})),
/**
* whether enable X-Frame-Options response header
*/
Expand Down
12 changes: 5 additions & 7 deletions src/lib/extend/safe_curl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,23 @@ export type HttpClientRequestReturn = ReturnType<HttpClient['prototype']['reques
* @return {Promise} response
*/
export async function safeCurlForApplication(this: EggCore, url: HttpClientRequestURL, options: HttpClientOptions = {}): HttpClientRequestReturn {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const app = this;
const ssrfConfig = app.config.security.ssrf;
const ssrfConfig = this.config.security.ssrf;
if (ssrfConfig?.checkAddress) {
options.checkAddress = ssrfConfig.checkAddress;
} else {
app.logger.warn('[@eggjs/security] please configure `config.security.ssrf` first');
this.logger.warn('[@eggjs/security] please configure `config.security.ssrf` first');
}

if (ssrfConfig?.checkAddress) {
let httpClient = app[SSRF_HTTPCLIENT] as ReturnType<EggCore['createHttpClient']>;
let httpClient = this[SSRF_HTTPCLIENT] as ReturnType<EggCore['createHttpClient']>;
// use the new httpClient init with checkAddress
if (!httpClient) {
httpClient = app[SSRF_HTTPCLIENT] = app.createHttpClient({
httpClient = this[SSRF_HTTPCLIENT] = this.createHttpClient({
checkAddress: ssrfConfig.checkAddress,
});
}
return await httpClient.request(url, options);
}

return await app.curl(url, options);
return await this.curl(url, options);
}
Loading

0 comments on commit 7b357c1

Please sign in to comment.