1

I am attempting to add a security token to all my AJAX $.post calls.

I set up the security token to be automatically added using the following code

$.ajaxSetup({
     beforeSend: function (jqXHR, settings) {
        settings.data += "&sessionID="+v_sessionID;
  }
});

and then code such as the following, will have the security token automatically appended

$.post("ajax/p_getOnePosition.jsp", {
    positionNo: positionNo,
}, function(response2) {

The code works well, but not for functions with no parameters such as

$.post("ajax/p_clearFilters.jsp", {

}, function(response2) {

Any idea why this should be?

I can fix it by simply adding a dummy parameter dummy:1 to the code

 $.post("ajax/p_clearFilters.jsp", {
       dummy:1
    }, function(response2) {

So I tried to do

 $.ajaxSetup({
     beforeSend: function (jqXHR, settings) {
        var noParameters=(settings.data==null || settings.data==undefined || settings.data=='');
        settings.data += (noParameters?"dummy=1":"") +"&sessionID="+v_sessionID;
  }
});

but this did not mimic having the dummy=1 manually added, and the security token was not available in the request.

UPDATE

I realize in retrospect (after @Rory McCrossan's comment and @Louys Patrice Bessette's answer) that my question was incomplete. I should have also included in my question the JSP code that I use to retrieve the parameter.

<%
String csrfSessionID = SecurityIssues.StringToAlphaNumericStr(request.getParameter("sessionID"));
%>
gordon613
  • 2,770
  • 12
  • 52
  • 81
  • 1
    I'm unable to replicate the issue: https://jsfiddle.net/RoryMcCrossan/5ng8kohm/. If you check the request in the network tab of the console you'll see the `&sessionId` value in the request payload. ***However*** the leading `&` on the key in that case could possibly be causing an issue in your server side. Try improving the logic so the `&` is only added when necessary. – Rory McCrossan Jan 10 '21 at 16:38
  • Thank you very much @RoryMcCrossan for taking the time to try and replicate the issue. From running your code I see - as you write - that the sessionId value is in the "Request Payload". But when the //positionNo:1 is uncommented then both the PositionNo and the sessionId value are displayed as "Form Data". And it seems I am only able to retrieve successfully the data from "Form Data" and not "Request Payload". Any ideas why this might be? – gordon613 Jan 10 '21 at 17:01
  • Also I did attempt to deal with the leading `&` in the code at the end of my question. Thanks! – gordon613 Jan 10 '21 at 17:02

2 Answers2

1

You have three data cases:

  • undefined
  • empty
  • not empty

Try that beforeSend function:

$.ajaxSetup({
  beforeSend: function (jqXHR, settings) {
    
    // Undefined data
    settings.data = settings.data === undefined ? "" : settings.data;

    // Add the & or not in front of the sessionID
    settings.data +=
      (settings.data.length > 0 ? "&" : "") + "sessionID=SESSION_ID";
    console.log("before send:", settings.data);
    
  }
});

The below snippet always ends up in an error because the request url is https://example.com. ;)

$.ajaxSetup({
  beforeSend: function (jqXHR, settings) {
    
    // Undefined data
    settings.data = settings.data === undefined ? "" : settings.data;

    // Add the & or not in front of the sessionID
    settings.data +=
      (settings.data.length > 0 ? "&" : "") + "sessionID=SESSION_ID";
    console.log("before send:", settings.data);
    
  }
});

$(".test").on("submit", function (e) {
  console.clear();
  e.preventDefault();

  let formId = $(this)[0].id;
  console.log( `You are trying the ${formId}`);

  let formValues;
  switch (formId) {
    
    case "test_1":
      // Do not set formValues on purpose...
      break;
    
    case "test_2":
      formValues = {};
      break;

    case "test_3":
      formValues = { firstName: "John", lastName: "Doh" };
      break;

  }

  console.log("on submit:", formValues);

  $.post("https://example.com", formValues)
    .done(function () {
      console.log("DONE");
    })
    .fail(function () {
      console.error("ERROR - (obviously!) - Check the Network tab-> example.com -> Headers -> Form Data");
    });
});
button{
  margin: 1em;
  width: 20em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form class="test" id="test_1">
  <button>Test #1 - Send an undefined object</button>
</form>

<form class="test" id="test_2">
  <button>Test #2 - Send an empty object</button>
</form>

<form class="test" id="test_3">
  <button>Test #3 - Send an object</button>
</form>

Also on CodePen

Louys Patrice Bessette
  • 33,375
  • 6
  • 36
  • 64
  • Thank you very much for your long and detailed and helpful answer. After working through it, it led me to finding the problem. I updated my question a bit because I realize in retrospect it could have been more complete. Appreciated! – gordon613 Jan 12 '21 at 12:56
0

After working through @Rory McCrossan's comment and @Louys Patrice Bessette's answer - thank you very much - I see that when beforeSend adds to an empty parameter list, then the SESSIONID is sent as part of the Request Payload, and when beforeSend adds to pre-existing parameter list, then SESSIONID is sent as part of the Form Data. This makes a difference in retrieving the parameters.

For data as part of the Form Data then it can be retrieved by the following:

String csrfSessionID = SecurityIssues.StringToAlphaNumericStr(request.getParameter("sessionID"));

For data as part of the request Payload it can be retrieved by the following: See @Fizer Khan's answer in Getting request payload from POST request in Java servlet

StringBuilder buffer = new StringBuilder();
java.io.BufferedReader reader = request.getReader();
String line;
while ((line = reader.readLine()) != null) {
    buffer.append(line);
    buffer.append(System.lineSeparator());
}
String data = buffer.toString();
System.out.println("data:"+data);

These two code snippets are mutually exclusive. The first code cannot retrieve from the Request Payload, and the second code cannot retrieve from the Form Data

Note that probably a better answer would force the beforeSend to send the SessionID in the Form Data in all cases, but this is a good workaround for now!

gordon613
  • 2,770
  • 12
  • 52
  • 81