node.jsreactjsstoragewasabi-hot-cloud-storage

How to store images securely and allow access only for user [React]


I'm building a tool with ReactJS where (logged in) users can upload images to some kind of gallery that they can access from there user account whenever they like.

I plan to upload the data directly to a cloud storage (most likely wasabi) and store them there.

What are best pratices to let users access images in a secure way? Of course the user that uploaded the images, should be able to see them in his gallery, but no other user. I mean I can of course only show the user associated images in the galleries, but i am concerned about data protection and also direct access to the images. Is it enough to store the files e.g. in a folder with a hashed name, so that no one can guess the image path? Or are some other restrictions necessary? I just don't see how I can additionally restrict access to the images to be displayed in the account without drastically degrading the user experience.

Happy to read your thoughts.

Thanks!


Solution

  • I had a similar issue where I couldn't simply give the URL of the image resource since those image resources were specific to certain users. I had my API return a byte stream for the image & then in my react app consume it as follows

    images(id: string, cancelToken?: CancelToken): Promise<FileResponse> {
     let url_ = "pathtoendpoint/{id}";
    
     let options_ = <AxiosRequestConfig>{
       cancelToken,
       responseType: "blob",
       method: "GET",
       url: url_,
       headers: {
         Accept: "application/octet-stream",
         Authorization: "Bearer ezfsdfksf...."
       },
     };
    
        
     return Axios.create().request(options_).then((_response: AxiosResponse) => 
     { 
       return new Promise<FileResponse>(_response.data);
     });
    
    } 
    
    export interface FileResponse {
      data: Blob;
      status: number;
      fileName?: string;
      headers?: { [name: string]: any };
    }
    

    I then create an ephemeral DOM string containing a uri

    let uri = URL.createObjectURL(data)
    

    Once I have the uri then I can display it as so

    <img src={uri} id="someId" alt="" />
    

    By following this approach, I'm treating the image bytes as any other type of data, be it string or number or boolean. And, can secure that resource.

    Here's what my server side controller method looks like, I'm using .NET core but you'll follow a similar approach with any other platform

    [Produces("application/octet-stream")]
    public async Task<ActionResult> GetImageById([FromRoute] Guid id)
    {
        var resource = await DatalayerService.GetImageAsync(id);
    
        return File(resource.Filebytes, resource.ContentType);
    }