bithavoc / express-winston

express.js middleware for winstonjs
https://www.npmjs.com/package/express-winston
MIT License
798 stars 186 forks source link

Filter authorization header by default #62

Closed gingermusketeer closed 8 months ago

gingermusketeer commented 9 years ago

Currently it is not straight forward to filter the authorization header. It would be nice if there was a flag or an easy way to do this.

Perhaps this should be on by default.

Here is what i am currently doing

function customRequestFilter(req, propName){
  if(propName === "headers"){
    return Object.keys(req.headers).reduce(function(filteredHeaders, key){
      if(key !== "authorization"){
        filteredHeaders[key] = req.headers[key]
      }
      return filteredHeaders
    }, {})
  } else {
    return req[propName]
  }
}

module.exports = expressWinston.logger({
    transports: transports,
    requestFilter: customRequestFilter
 })
krsyoung commented 9 years ago

Hey @gingermusketeer looks like you did most of the work here :-) I'm using the same approach to filter out cookies. Would it make sense to have a more generic approach to this or are folks thinking the custom requestFilter is the right way to do it?

Something like blacklist('headers', ['cookie', 'authorization']) would be nice.

I'll take a stab at it if it makes sense to folks.

gingermusketeer commented 8 years ago

@krsyoung glad it helped :)

adamhadani commented 8 years ago

very helpful guys, thanks!

sourcec0de commented 6 years ago

In case anyone is interested in my lodash implementation.

const redacted = '[REDACTED]'
function redactInsecureRequestData (req, propName) {

    if (propName === 'headers') {
        return _
            .chain(req)
            .get(propName)
            .cloneDeep()
            .set('cookie', redacted)
            .set('authorization', redacted)
            .value()
    }

    return req[propName]
}
LiranBri commented 6 years ago

note that if you need to know what header was censored, then @gingermusketeer's solution would remove it without hint of what was removed, and @sourcec0de's solution would set this [REDACTED] string even if there was no header cookie or authorization in the first place.

to only censor the field if header exists, use:

const redacted = '[REDACTED]'
function redactInsecureRequestData (req, propName) {
  if (propName === 'headers') {
    return _
      .chain(req)
      .get(propName)
      .cloneDeep()
      .assign(_.pick({
        'authorization': redacted,
        'cookie': redacted
      }, _.keys(req[propName])))
      .value()
  }
  return req[propName]
}
marlonbernardes commented 5 years ago

Another approach, using Ramda:

import { mapObjIndexed } from 'ramda'

const blacklist = ['authorization', 'cookie' /*, ... */] 
const omitHeader = (value, header) => blacklist.includes(header) ? '[REDACTED]' : value

const requestFilter = (req, propName) => {
  return propName === 'headers' ? mapObjIndexed(omitHeader, req.headers) : req[propName]
}