Git Product home page Git Product logo

Comments (7)

glasser avatar glasser commented on May 2, 2024

Have you read the docs about the CSRF prevention feature, including the specific section about graphql-upload? https://www.apollographql.com/docs/apollo-server/security/cors/#preventing-cross-site-request-forgery-csrf

from apollo-server.

rpateld avatar rpateld commented on May 2, 2024

I'm trying to understand this topic but the documentation is too confusing for me. I need a simple example to follow along. This is the code I wrote but it's not working as expected. Can you please take a look and tell me what I'm doing wrong? I'm really stuck and frustrated. Thanks for your help.

import { createWriteStream, unlink } from "fs";
import { ApolloServer } from "@apollo/server";
import { expressMiddleware } from "@apollo/server/express4";
import express from "express";
import pkg from "body-parser";
import cors from "cors";
import mkdirp from "mkdirp";
import shortid from "shortid";
import { schema } from "./schema.js";
import dotenv from "dotenv";
dotenv.config();
const app = express();
const { json } = pkg;

const UPLOAD_DIR = "./uploads";
// Ensure upload directory exists.
mkdirp.sync(UPLOAD_DIR);

/**
 * Stores a GraphQL file upload. The file is stored in the filesystem and its
 * metadata is recorded.
 * @param {GraphQLUpload} upload GraphQL file upload.
 * @returns {object} File metadata.
 */

const storeUpload = async (upload) => {
  console.log("####upload###");
  const { createReadStream, filename, mimetype } = await upload;
  const stream = createReadStream();
  const id = shortid.generate();
  const path = `${UPLOAD_DIR}/${id}-${filename}`;
  const file = { id, filename, mimetype, path };

  await new Promise((resolve, reject) => {
    stream
      .on("error", (error) => {
        unlink(path, () => {
          reject(error);
        });
      })
      .pipe(createWriteStream(path))
      .on("error", reject)
      .on("finish", resolve);
  });
  return file;
};

const server = new ApolloServer({
  csrfPrevention: false,
  schema,
  context: { storeUpload },
});

await server.start();

const PORT = 5031;

app.use("/graphql", cors(), json(), expressMiddleware(server));

app.listen(PORT, () => {
  console.log(`File Server listening on port ${PORT}/graphql`);
});

from apollo-server.

glasser avatar glasser commented on May 2, 2024

The change you need to make is in your client. The protocol designed for graphql uploads contains a severe vulnerability for any server that uses cookies to authenticate, unless both the server and client work together to avoid the security issue. (This vulnerability will allow any website on the internet to get browsers to run mutations against your server with the visitor's cookies, even if your server tries to use CORS to restrict your API's usage to trusted servers.)

Apollo Server works by default to prevent this problem; you need to configure your client to work with it. What package are you using to implement GraphQL uploads on the client side?

(You should not add csrfPrevention: false to your server unless you are 100% positive you understand the CSRF threat model intimately and your server is not vulnerable to it.)

from apollo-server.

rpateld avatar rpateld commented on May 2, 2024

For mutation, I am using GraphQLUpload here is the code, I am using Graphaql Playground to test my upload for my client.

import { GraphQLList, GraphQLObjectType, GraphQLNonNull } from "graphql";
import GraphQLUpload from "graphql-upload/GraphQLUpload.mjs";
import { FileType } from "./File.js";

export const MutationType = new GraphQLObjectType({
  name: "Mutation",
  fields: () => ({
    singleUpload: {
      description: "Stores a single file.",
      type: new GraphQLNonNull(FileType),
      args: {
        file: {
          description: "File to store.",
          type: new GraphQLNonNull(GraphQLUpload),
        },
      },
      resolve: (parent, { file }, { storeUpload }) => storeUpload(file),
    },
    multipleUpload: {
      description: "Stores multiple files.",
      type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(FileType))),
      args: {
        files: {
          description: "Files to store.",
          type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(GraphQLUpload))),
        },
      },
      async resolve(parent, { files }, { storeUpload }) {
        const uploadedFiles = [];

        for (const file of files) {
          try {
            const uploadedFile = await storeUpload(file);
            uploadedFiles.push(uploadedFile);
          } catch (error) {
            console.error(`${error.name}: ${error.message}`);
          }
        }

        return uploadedFiles;
      },
    },
  }),
});

from apollo-server.

glasser avatar glasser commented on May 2, 2024

That's server code still. I don't know if graphql-playground can be adapted to use the better protocol (last I checked the project had been explicitly unmaintained for years).

from apollo-server.

rpateld avatar rpateld commented on May 2, 2024

Sorry, I am using Introspection and not graphql-playground.

from apollo-server.

github-actions avatar github-actions commented on May 2, 2024

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
For general questions, we recommend using StackOverflow or our discord server.

from apollo-server.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.