helmetjs / helmet

Help secure Express apps with various HTTP headers

Home Page:https://helmetjs.github.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Retrieving data from memory is displayed incorrectly

chrisdel101 opened this issue · comments

I check user IPs and store their results in a cache for a hour to save DB calls. The data is binary (image data) and when returned from the cache it is displayed as gibberish rather than a proper image. It also can prompt a gibberish text file to download (browser dependant). What would cause Helmet to do this?

It displays correctly when not delivered from memory.

This is my App.js file. Are there any red flags here causing a conflict with Helmet?

const helmet = require("helmet");
const app = express()

app.use(helmet());
// view engine setup
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'pug')

app.set('trust proxy', 'loopback')

app.locals = {
  title: 'MyApp',
  ENV,
}

app.use(morgan('dev'))
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: true }))

app.use(cookieParser(''))
app.use(express.static(path.join(__dirname, 'public')))

app.use('/', index)

//error logging
app.use(
  expressWinston.errorLogger({
    transports: [new winston.transports.Console()],
    format: winston.format.combine(
      winston.format.colorize(),
      winston.format.json()
    ),
  })
)
// // catch 404 and forward to error handler
app.use(function (req, res, next) {
  const err = new Error('404 Not Found')
  err.status = 404
  next(err)
})

//access logging
const accessLogStream = fs.createWriteStream(
  path.join(__dirname, 'access.log'),
  {
    flags: 'a',
  }
)

// express-winston errorLogger makes sense AFTER the router.
app.use(
  expressWinston.errorLogger({
    transports: [
      new winston.transports.File({
        filename: 'error.log',
        level: 'error',
      }),
    ],
    format: winston.format.combine(
      winston.format.colorize(),
      winston.format.json()
    ),
  })
)
const errorController = require('./logic/controllers/error.controller')
app.use(function (err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message
  res.locals.error = req.app.get('env') === 'development' ? err : {}
  res.status(err.status || 500)
  // render the error page
  errorController.showErrorPage(req, res, err)
})

Express: express@4.18.1
Helmet: Latest
Node: v16.14.2

I cannot think of a reason this would be happening.

Can you make a smaller sample app that reproduces this problem? Does removing Helmet solve the issue? What happens if you load the resource with curl?

So I know what is causing this: not setting res.type('image/jpg') causes a image not to render properly i.e. show up as raw data. I do set this, but for some reason when loading from the cache it is not working properly.

This only happens after installing Helmet. It works as expected otherwise. I wanted to use Helmet since I am getting attacked alot lately.

I'll do more debugging and/or a make a minimal example + write back once more info to report.

Ah, I suspect I know what's causing this.

In the absence of a Content-Type header, Helmet disables MIME sniffing by default. It does this with the X-Content-Type-Options header. It does this for security reasons, as MIME sniffing can sometimes cause problems.

That would explain why Helmet causes the data to be interpreted as plain bytes. Without Helmet and without a MIME type, browsers identify the bytes as JPEG. I recommend setting the Content-Type header for all of your responses, which is done in Express with res.type.

I'm going to close this because I'm pretty sure this is your problem, but let me know if that's wrong and I'll reopen.

I am setting res.type when serving a fresh image with res.type('image/jpg'), but when loading from the cache I was not setting it again.

By manually setting it again, the issue appears to be solved. Thx!