0

I'm using @nestjs/swagger in the Nest.js application to generate Swagger documentation.

In the documentation we have a simple example like

      const config = new DocumentBuilder()
        .setTitle('Cats example')
        .setDescription('The cats API description')
        .setVersion('1.0')
        .addTag('cats')
        .build();
      const document = SwaggerModule.createDocument(app, config);
      SwaggerModule.setup('api', app, document);

With this implementation, I faced the security issue, which can expose attackers to phishing. For example, we have a swagger page

https://petstore.swagger.io/

Attackers can add a query parameter in URL like

https://petstore.swagger.io/?url=https://27.rs/card.yaml#/default/get_

That can lead to security issues. Is there any way to prevent it? Can we disable the query parameters for the Swagger URL, or clean it? To convert

https://petstore.swagger.io/?url=https://27.rs/card.yaml#/default/get_ => https://petstore.swagger.io/

As a 4-th parameter SwaaggerModule.setup function can receive options. I have tried to do something with them but still no result. Here are possible parameters

export interface SwaggerCustomOptions {
  explorer?: boolean;
  swaggerOptions?: Record<string, any>;
  customCss?: string;
  customCssUrl?: string;
  customJs?: string;
  customfavIcon?: string;
  swaggerUrl?: string;
  customSiteTitle?: string;
  validatorUrl?: string;
  url?: string;
  urls?: Record<'url' | 'name', string>[];
}

I can see also the open issue in GitHub regarding this question. There are mentioned about the usage of window.history.replaceState(null, "", window.location.pathname);. How it can be used in @nestjs/swagger?

CyberEternal
  • 2,259
  • 2
  • 12
  • 31
  • how did you build that swagger page? because the one generated by `@nestjs/swagger` doesn't this issue – Micael Levi Jun 24 '21 at 20:45
  • You can try to run the Nest.js server and build a swagger document as we have in the documentation. After you can open the swagger page and add query parameter such as `url=https://27.rs/card.yaml#/default/get_`. For example, your URL can look like `http://localhost:3000/api/doc/url=https://27.rs/card.yaml#/default/get_` – CyberEternal Jun 24 '21 at 21:14
  • For the locally, you can face a CORS error. The goal is to prevent providing query parameters to prevent security issues. – CyberEternal Jun 24 '21 at 21:16
  • you're right! I don't think that we can fix that as a user of `@nestjs/swagger` due to [this line](https://github.com/nestjs/swagger/blob/491b168cbff3003191e55ee96e77e69d8c1deb66/lib/swagger-module.ts#L55) (in case of `express` http adpater) – Micael Levi Jun 25 '21 at 01:35
  • the far I could get is disallow the `url` query param for our swagger page, ie., if you request `http://localhost:3000/api?url=https://27.rs/card.yaml#/default/get_` you'll get 403 I didn't succeed overwriting this param value (following [this](https://stackoverflow.com/questions/18801661/)) – Micael Levi Jun 25 '21 at 02:17
  • Yup. Actually, as a temporary solution, I have added something like ` app.use( `/${swaggerPath}`, (req: Request, res: Response, next: NextFunction) => { if (Object.keys(req.query).length) { res.redirect(`/${swaggerPath}`); } else { next(); } }, );` before calling `SwaggerModule.setup(swaggerPath, app, document);` – CyberEternal Jun 25 '21 at 05:31

1 Answers1

0

I didn't found any solution in @nestjs/swagger and I can see the open issue in GitHub

https://github.com/swagger-api/swagger-ui/issues/4332#issuecomment-867574178

As a temporary solution, I have added the following part of the code to handle the requests before rendering the Swagger document.

   app.use(swaggerPath, (req: Request, res: Response, next: NextFunction) => {
      // A temporary solution to prevent security issues with query params
      // Can be removed when into the swagger module will be added ability to turn off query parameters of URL
      if (Object.keys(req.query).length) {
        res.redirect(swaggerPath);
      } else {
        next();
      }
    });

Where swaggerPath is something like /api/doc, or your swagger path.

CyberEternal
  • 2,259
  • 2
  • 12
  • 31