Search code examples
c#azureasp.net-mvc-4multipartform-data.net-4.8

Azure WAF Intermittent Blocking Html FileInput with General 200002 and 200003 Violations


I have an older MVC (I think v4, it is written in .Net 4.8) web application that we moved behind AFD and enabled all of the default WAF rules in Blocking mode.

Sometimes users cannot upload images through an html form. According to the logs, I am getting the following failures:

  • Microsoft_DefaultRuleSet-2.1-General-200002
    details_matches_s: [{"matchVariableName":"ParseBodyError","matchVariableValue":"1"}]
  • Microsoft_DefaultRuleSet-2.1-General-200003
    details_matches_s : []

I did see this post but with it being 2 years old I was hoping MSFT would have had a fix by now. Disabling the rules entirely is less than ideal, which is why I'm looking to see if there is anything I can be doing in code to make the file upload always succeed. For instance, should I be using a different HTTP Method than POST?

The form:

 <form method="POST" action="@urlForSavingLogo" enctype="multipart/form-data">
        <p>
            Browse to an image on your computer and then click the Upload button.
        </p>
        <p>Image formats supported: .png and .jpg</p>

        <p>Optimal pixel height for logo: @Model.OptimalHeightInPx</p>
        
        <ul>
            <li>Supports smaller images</li>
            <li>
                Please note: Logos smaller than the optimal size will not be resized.
            </li>
            <li>We recommend .png at 300dpi for best quality</li>
        </ul>
        <br />
        <div class="form-group">
            <label for="image">@Model.Title</label><br />
            <input id="image" class="hiddenInput" type="file" name="image" />
            <button id="uploadButton" class="btn btn-default">Browse...</button>
            &nbsp;
            <span id="selectedFileName">No file selected</span>
        </div>
    </form>

The Controller Action:

[HttpPost]
public RedirectResult SaveWebsiteLogo(HttpPostedFileBase image)
{
    // omitted for brevity
}

And just for clarity, here's how the form functions with javascript to select the file when the browse button is clicked.

//trigger click of hidden input
$("body").on('click', '#uploadButton', function (e) {
    e.preventDefault();
    $('#image').click();
});

$("body").on('change', '#image', function () {
    populateSelectedFileName();
});

Sometimes, we get the two errors blocking the upload, and sometimes we do not. I am trying to figure out why. The fact it is intermittent leads me to believe it might be due to something with the encoding or size of the image.


Solution

    • Microsoft_DefaultRuleSet-2.1-General-200002
      details_matches_s: [{"matchVariableName":"ParseBodyError","matchVariableValue":"1"}]

    This rule is triggered when the WAF has trouble if the request body is large, not well-formed, or doesn’t support to standard formats.

    • Microsoft_DefaultRuleSet-2.1-General-200003
      details_matches_s : []

    This rule comes when requests with an empty body, or it flags requests where the content type doesn’t align with the request body structure.

    • The code setup for file upload with POST and multipart/form-data is correct for handling images. But WAF is likely flagging this as suspicious due to the request body content or size, not the HTTP method itself.

    I have seen the old post that which you referred, there is no further update from the MSFT as @GitaraniSharma-MSFT suggests Content-Type header should matches the file type (e.g., image/jpeg for JPEG images or image/png for PNG files).

    • When using JavaScript to handle the file selection and upload, check that the file’s MIME type is set appropriately in any AJAX request headers if you’re sending the upload that way.

    AJAX with FormData for Controlled File Uploads:

    $('#image').on('change', function () {
        const file = this.files[0];
        const maxSize = 128 * 1024; // Example size limit (128 KB)
    
        if (file && file.size > maxSize) {
            alert("File size must be under 128 KB.");
            $(this).val(''); // Clear the input if the file is too large
        } else {
            const formData = new FormData();
            formData.append("image", file);
    
            $.ajax({
                url: '@Url.Action("SaveWebsiteLogo", "YourController")',
                type: 'POST',
                data: formData,
                contentType: false, // Let jQuery set the correct Content-Type
                processData: false,
                success: function (response) {
                    alert('Image uploaded successfully');
                },
                error: function (jqXHR, textStatus, errorThrown) {
                    alert('Upload failed: ' + errorThrown);
                }
            });
        }
    });