0

In order to become more familiar with django, I decided to build a website which is gonna let a user upload a csv file, which is then gonna be converted to excel and the user will be able to download it.

In order to achieve that I created a modelform with one model FileField called csv_file as shown below:

#models.py

class CSVUpload(models.Model):
    csv_file = models.FileField(upload_to="csvupload/")

    def __str__(self):
        return self.csv_file


#forms.py   
class CsvForm(forms.ModelForm):
    class Meta:
        model = CSVUpload
        fields = ('csv_file', )

and the corresponding view is:

from django.shortcuts import render, redirect
import pandas as pd
import os

#converts file from csv to excel  
def convertcsv2excel(filename):
    fpath = os.path.join(settings.MEDIA_ROOT + "\csvupload", filename)
    df = pd.read_csv(fpath)
    newfilename = str(filename) +".xlsx"
    newpathfile = os.path.join(settings.MEDIA_ROOT, newfilename)
    df.to_excel(newpathfile, encoding='utf-8', index=False)
    return newfilename

def csvtoexcel(request):
    if request.method == 'POST':
        form = CsvForm(request.POST, request.FILES)
        if form.is_valid():
           form.save()
           print(form.cleaned_data['csv_file'].name)
           convertcsv2excel(form.cleaned_data['csv_file'].name)
           return redirect('exceltocsv')
    else:
        form = CsvForm()
    return render(request, 'xmlconverter/csvtoexcel.html',{'form': form})

right now as you can see I am using Pandas in order to convert the csv file to excel inside the views.py file. My question is, is there a better way to do it (for instance in the form or model module) in order to make the excel file more effectively downloadable?

I appreciate any help you can provide!

marialadelbario
  • 325
  • 1
  • 4
  • 19

1 Answers1

1

First, I want to point out that your example demonstrates an arbitrary file upload vulnerability. Pandas does not validate the format of the file for you, so as an attacker, I can simply upload something like malware.php.csv to your conversion script, and any malicious code I include will remain intact. Since you aren't validating that this file's contents are, in fact, in CSV format, then you are giving users a means to directly upload a file with an arbitrary extension and possibly execute code on your website. Since you are rendering the xlsx format on the webpage the way you are, there's a good chance someone could abuse this. If this is just your own personal experiment to help yourself get familiar, that's one thing, but I strongly recommend against deploying this in production. What you are doing here is very dangerous.

As for your more immediate problem, I'm not personally familiar with Django, but this looks very similar to this question: Having Django serve downloadable files

In your case, you do not want to actually save the file's contents to your server but rather you want to process the file contents and return it in the body of the response. The django smartfile module looks to be exactly what you want: https://github.com/smartfile/django-transfer

This provides components for Apache, Nginx, and lighttpd and should allow you to provide a means to provide files in the response immediately following a request to upload/convert the file. I should emphasize that you need to be very careful about where you save these files, validating their contents, ensure end-users cannot browse to or execute these files under the web server context, and that they are deleted immediately after the response and file is successfully sent.

Someone more familiar with Django can feel free to correct me or provide a usable code example, but this kind of functionality, in my experience, is how you introduce code execution into your site. It's usually a bad idea.

True Daemon
  • 126
  • 4