Sanitize sensitive fields in request header and body in logger (#5279)
* Sanitize sensitive fields in request header and body in logger * fix: log request headers, body, and query only when debug logs are enabled
This commit is contained in:
parent
6f94d61f22
commit
2ae4678da4
|
|
@ -38,6 +38,8 @@ PORT=3000
|
||||||
# DEBUG=true
|
# DEBUG=true
|
||||||
# LOG_PATH=/your_log_path/.flowise/logs
|
# LOG_PATH=/your_log_path/.flowise/logs
|
||||||
# LOG_LEVEL=info #(error | warn | info | verbose | debug)
|
# LOG_LEVEL=info #(error | warn | info | verbose | debug)
|
||||||
|
# LOG_SANITIZE_BODY_FIELDS=password,pwd,pass,secret,token,apikey,api_key,accesstoken,access_token,refreshtoken,refresh_token,clientsecret,client_secret,privatekey,private_key,secretkey,secret_key,auth,authorization,credential,credentials
|
||||||
|
# LOG_SANITIZE_HEADER_FIELDS=authorization,x-api-key,x-auth-token,cookie
|
||||||
# TOOL_FUNCTION_BUILTIN_DEP=crypto,fs
|
# TOOL_FUNCTION_BUILTIN_DEP=crypto,fs
|
||||||
# TOOL_FUNCTION_EXTERNAL_DEP=moment,lodash
|
# TOOL_FUNCTION_EXTERNAL_DEP=moment,lodash
|
||||||
# ALLOW_BUILTIN_DEP=false
|
# ALLOW_BUILTIN_DEP=false
|
||||||
|
|
|
||||||
|
|
@ -193,28 +193,71 @@ requestLogger = createLogger({
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function getSensitiveBodyFields(): string[] {
|
||||||
|
return (process.env.LOG_SANITIZE_BODY_FIELDS as string)
|
||||||
|
.toLowerCase()
|
||||||
|
.split(',')
|
||||||
|
.map((f) => f.trim())
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSensitiveHeaderFields(): string[] {
|
||||||
|
return (process.env.LOG_SANITIZE_HEADER_FIELDS as string)
|
||||||
|
.toLowerCase()
|
||||||
|
.split(',')
|
||||||
|
.map((f) => f.trim())
|
||||||
|
}
|
||||||
|
|
||||||
|
function sanitizeObject(obj: any): any {
|
||||||
|
if (!obj || typeof obj !== 'object') return obj
|
||||||
|
|
||||||
|
const sensitiveFields = getSensitiveBodyFields()
|
||||||
|
const sanitized = Array.isArray(obj) ? [...obj] : { ...obj }
|
||||||
|
Object.keys(sanitized).forEach((key) => {
|
||||||
|
const lowerKey = key.toLowerCase()
|
||||||
|
if (sensitiveFields.includes(lowerKey)) {
|
||||||
|
sanitized[key] = '********'
|
||||||
|
} else if (typeof sanitized[key] === 'string') {
|
||||||
|
if (sanitized[key].includes('@') && sanitized[key].includes('.')) {
|
||||||
|
sanitized[key] = sanitized[key].replace(/([^@\s]+)@([^@\s]+)/g, '**********')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return sanitized
|
||||||
|
}
|
||||||
|
|
||||||
export function expressRequestLogger(req: Request, res: Response, next: NextFunction): void {
|
export function expressRequestLogger(req: Request, res: Response, next: NextFunction): void {
|
||||||
const unwantedLogURLs = ['/api/v1/node-icon/', '/api/v1/components-credentials-icon/', '/api/v1/ping']
|
const unwantedLogURLs = ['/api/v1/node-icon/', '/api/v1/components-credentials-icon/', '/api/v1/ping']
|
||||||
|
|
||||||
if (/\/api\/v1\//i.test(req.url) && !unwantedLogURLs.some((url) => new RegExp(url, 'i').test(req.url))) {
|
if (/\/api\/v1\//i.test(req.url) && !unwantedLogURLs.some((url) => new RegExp(url, 'i').test(req.url))) {
|
||||||
// Create a sanitized copy of the request body
|
const isDebugLevel = logger.level === 'debug' || process.env.DEBUG === 'true'
|
||||||
const sanitizedBody = { ...req.body }
|
|
||||||
if (sanitizedBody.password) {
|
|
||||||
sanitizedBody.password = '********'
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use the shared requestLogger with request-specific metadata
|
const requestMetadata: any = {
|
||||||
const requestMetadata = {
|
|
||||||
request: {
|
request: {
|
||||||
method: req.method,
|
method: req.method,
|
||||||
url: req.url,
|
url: req.url,
|
||||||
body: sanitizedBody, // Use sanitized body instead of raw body
|
params: req.params
|
||||||
query: req.query,
|
|
||||||
params: req.params,
|
|
||||||
headers: req.headers
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only include headers, body, and query if log level is debug
|
||||||
|
if (isDebugLevel) {
|
||||||
|
const sanitizedBody = sanitizeObject(req.body)
|
||||||
|
const sanitizedQuery = sanitizeObject(req.query)
|
||||||
|
const sanitizedHeaders = { ...req.headers }
|
||||||
|
|
||||||
|
const sensitiveHeaders = getSensitiveHeaderFields()
|
||||||
|
sensitiveHeaders.forEach((header) => {
|
||||||
|
if (sanitizedHeaders[header]) {
|
||||||
|
sanitizedHeaders[header] = '********'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
requestMetadata.request.body = sanitizedBody
|
||||||
|
requestMetadata.request.query = sanitizedQuery
|
||||||
|
requestMetadata.request.headers = sanitizedHeaders
|
||||||
|
}
|
||||||
|
|
||||||
const getRequestEmoji = (method: string) => {
|
const getRequestEmoji = (method: string) => {
|
||||||
const requetsEmojis: Record<string, string> = {
|
const requetsEmojis: Record<string, string> = {
|
||||||
GET: '⬇️',
|
GET: '⬇️',
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue