0

I am working on a ASP.NET web page and have gotten the AntiForgeryTokens working for most POST actions. The one I cannot make work is the uploading of a file. I see the token correctly populated in the url, with the other variables, yet the Controller claims that __RequestVerificationToken is not present.

Web Page Code, includes embedded JavaScript/Jquery at the end

 @using (Html.BeginForm()) {
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)

    <div class="vs30px"> &nbsp; </div>
    <div id="division" class="hide_overflow ">

    <div class="vs30px"> &nbsp; </div>
    <div id="division" class="hide_overflow ">
    <table class="Editw_table">
        <tbody>
             <tr>        
                <td colspan="2" >
                    <div>
                    <div style="font-weight:bold;">File Type: </div>
                    <select id="fileSetType">
                        @foreach (var item in Model)
                        {
                            <option value=" @Html.DisplayFor(modelItem => item.filesetTypeId) ">@Html.DisplayFor(modelItem => item.filesetTypeName)</option>
                        }
                    </select>
                    </div>      
                <br />
                </td>
            </tr>
            <tr>
                <td>
                <div  style="font-weight:bold;">File(s):</div>         
                </td>
            </tr>
            <tr>
                 <td >
                   <div class="fileList"></div>
                </td>
            </tr>       
        </tbody>        
    </table>
    <div id="submitTarget"></div>
        <form id="fileUpload" enctype="multipart/form-data">
            <input type="file" id="newFile" style="position:fixed; top: -1000px;"/>
            <div  style="font-weight:bold;"> Comments: </div>         
            <input type="text" id="filesetDetails" size="50" /><br />
        </form>
    </div>  

    <script>
        $(document).ready(function () {
            //uploads a fileset to the server. 
            $('#submitTarget').submit(function (event) {

                event.stopPropagation();

                var verToken = $('[name=__RequestVerificationToken]').val();
                var fileInput = $('#newFile')[0].files;      //the input tag containing the file information.
                var fileSetTypeName = $('#fileSetType :selected').text(); //fetch the file set type stored in the hidden field on the page. 
                var fileSetDetails = document.getElementById("filesetDetails").value;
                var url = "File\\FileUpload?__RequestVerificationToken=" + verToken + "&filesetType=" + fileSetTypeName + "&details=" + fileSetDetails;

                PostBinaryFile(url, fileInput[0]);
            });
        });
    </script>  
    }

JavaScript call to Upload the file

function PostBinaryFile(url, file) {
    var buffer = $('.MiddleOuterDiv').spinBuffer();

    var req = new   XMLHttpRequest();
    req.open('POST', url, true);
    req.setRequestHeader("Cache-Control", "no-cache");
    req.setRequestHeader("X-File-Name", file.name);
    req.setRequestHeader("X-File-Size", file.size);
    req.setRequestHeader("Content-type", "multipart/form-data");

    req.addEventListener("load", reqListener);
    req.addEventListener("error", reqListener);
    req.addEventListener("abort", reqListener);

    req.onload = null;
    req.send(file);
}

Finally the relevant controller code function

 [HttpPost]
 [ValidateAntiForgeryToken]
 [FileErrorHandler]
 public JsonResult FileUpload(string filesetType, string details)
 {
     //Create a new fileset via the API
     FileServices.FileSet fs = new FileServices.FileSet(filesetType, null, details, DateTime.Now, "SYSTEM");
      //Add each file
      string tempFileName = System.IO.Path.GetTempFileName();

      //Get the custom parameters provided
      string fileName = Request["HTTP_X-File-Name"];
      string fileSize = Request["HTTP_X-File-Size"];

      try
      {
          // Read the content of the binary input stream
          byte[] buffer = new byte[Request.InputStream.Length];
          int offset = 0;
          int cnt = 0;
          while ((cnt = Request.InputStream.Read(buffer, offset, 10)) > 0)
          {
              offset += cnt;
          }

          string temporaryFileName = System.IO.Path.GetTempFileName();

          // Write the input stream to a temporary file
          using (FileStream fstream = new FileStream(temporaryFileName, FileMode.Create))
          {
              fstream.Write(buffer, 0, buffer.Length);
              fstream.Flush();
          }

          // Add the zip archive's contents to the filesset.
         int count = fs.AddArchive(temporaryFileName, System.IO.Path.GetFileName(fileName), false);

          fs.SetComplete(true);

          var retVal = new JsonResult
              {
                   Data = new { success = true, error = "none", fileCount = count, message = "Uploaded " + count + " files" },
                   JsonRequestBehavior = JsonRequestBehavior.AllowGet
               };

          return retVal;
      }
      catch
      {
          FileServices.FileSet.DeleteFileSet(fs.FileSetId);
          throw;
      }
}
zgood
  • 12,181
  • 2
  • 25
  • 26
  • You have a `
    ` nested inside another `
    ` which is invalid. This is probably causing issues.
    – zgood Apr 26 '16 at 18:08
  • Does the token appear in the request body? Check the network request. – Jasen Apr 26 '16 at 18:12
  • @zgood I have removed the second
    and am getting the same result.
    – travisco_nabisco Apr 26 '16 at 18:55
  • @Jasen Yes, the token does appear in the body. I ran a WireShark capture to verify this. – travisco_nabisco Apr 26 '16 at 18:56
  • @travisco_nabisco I would replace `
    ` with `@using (Html.BeginForm("Action", "Controller", FormMethod.Post, new { id = "fileUpload", enctype = "multipart/form-data" })) { ... }` and put your `@Html.AntiForgeryToken()` inside that.
    – zgood Apr 26 '16 at 18:59
  • @zgood Tried that and had no luck. – travisco_nabisco Apr 26 '16 at 23:11
  • The frustrating part is that I have other pages and controllers where the validation is done correctly. The AntiForgeryToken is placed in the form data correctly and it all just works. – travisco_nabisco Apr 26 '16 at 23:12
  • Are those AJAX requests also? [This answer](http://stackoverflow.com/a/13622061/2030565) has some basics about how it works. This is also helpful http://haacked.com/archive/2011/10/10/preventing-csrf-with-ajax.aspx/. And finally you can step through the [actual code](https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/ValidateAntiForgeryTokenAttribute.cs) for the filter attribute. – Jasen Apr 26 '16 at 23:27
  • @Jasen No, the other requests are done directly through the form submittal. I'll take a look at the links you provided and see if I can find a solution. Thanks – travisco_nabisco Apr 27 '16 at 15:47

0 Answers0