I am using the below code for sanitizing the JSON but still, I am getting the JSON injection while scanning from Fortify can you please help me out what is the problem or this is not an issue, maybe suppress. I have also looked out for the same question but those don't solve my problem . my problem is that I am sanitizing my JSON before converting it to java object but still I am getting JSON injection error in fortify
public String handleEventMessage(String jsonRequest) {
MonerisPaymentDetailsObject paymentObject = null;
if(null!=jsonRequest && jsonRequest.length()>0){
try{
paymentObject = mapper.readValue(JsonSanitizer.sanitize(jsonRequest), MonerisPaymentDetailsObject.class);
}catch(Exception ex){
logger.error("Error occured while converting MonerisPaymentDetailsObject json to Object :" , ex);
}
return "abc";
}
Fortify giving below description for this error
1. Data enters a program from an untrusted source.
In this case the data enters at readLine() in EPWFPaymentServicesServlet.java at line 49.
2. The data is written to a JSON stream.
In this case the JSON is written by readValue() in EPWFMonerisPaymentsServiceHandler.java at line 46.
EPWFPaymentServicesServlet.java code where data is entered
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
CodeTimer timer = new CodeTimer("EPWFPaymentServicesServlet.doPost()", true);
response.setContentType("text/xml");
BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
StringBuffer requestBuffer = new StringBuffer(request.getContentLength());
String line = null;
while ((line = reader.readLine()) != null) {
requestBuffer.append(line).append('\n');
}
// read the POST request contents
String requestString = requestBuffer.toString();
if (logger.isDebugEnabled()) {
logger.debug("EPWF Payment Service POST Request: \n" + ((requestString == null) ? "Null" : requestString.substring(0, 9)));
}
PaymentServiceHandlerComposit paySvcHandler = new PaymentServiceHandlerComposit();
String responseString =paySvcHandler.handleEventMessage(requestString);//line no 49 where fortify is giving description for class where i am sanitizing the data
if (logger.isDebugEnabled()) {
logger.debug("EPWF Payment Service POST Response: \n" + ((responseString == null) ? "Null" : requestString));
}
response.getOutputStream().print(responseString);
timer.stopAndLogTiming("");
}
Given that you are using a new up-to-date version of jackson, there should be no need to pre-sanitise or alter your data at all before handing it off to jackson.
Jackson will only accept and parse valid JSON, as new exploits and vulnerabilities are discovered, the maintainers of Jackson fix and release new versions. and the best you can do is to keep up to date with these versions.
If the above conditions are met, you can safely suppress this error from fortify, the chance that there is a bug in your custom sanitizer is way higher than the chance of there being one in Jackson
Related
I am using Rest Assured Framework for API testing(Using Java).
At line (1),I am expecting error as there is mismatch in expected JSON response and Actual JSON response
But instead my code is executing successfully.
Can someone please tell me if I am doing anything wrong in below code?
public void test123() {
try {
//Read the Curl Request Input file
String json = input.readFromTextFile(
System.getProperty("user.dir") + "\\src\\test\\resources\\inputFile\\CurlDataFile.txt");
json = json.replaceAll(" ", "");
RestAssured.baseURI = "My URL";
given().
contentType("application/json").
body(json).
when().
post("").
then().
assertThat().body(matchesJsonSchemaInClasspath("testCurlOuput1.json")); (1)
} catch (IOException e) {
e.printStackTrace();
}catch(JsonSchemaValidationException e){
e.printStackTrace();
}
}
This is not directly relevant to REST-assured, but I suggest you take a look at Karate, because IMO it may be exactly what you are looking for.
One of the core features of Karate is that you can perform a full equality match of a JSON payload in one step.
And you can easily use JSON from files, which encourages the re-use of payloads across multiple tests.
You are catching all Exceptions. When your assertThat(..) fails, it throws an Exception. Put a breakpoint on the e.printStackTrace(); run in DEBUG mode and check that your AssertionException/Error isn't being caught.
Instead of catching exceptions, just add all Checked Exceptions to your test signature. If an exception is uncaught, it will fail the test. Alternatively, but less prefered in my opinion, resolve by putting fail(); in the catch block.
Finally I choose different library i.e. jayway.restassured library and then JSON Assert library (org.skyscreamer.jsonassert.JSONAssert) which will comapre actual and expected response.
public void test123() {
String postData = input.readFromTextFile(System.getProperty("user.dir") + "\\src\\test\\resources\\inputFile\\CurlDataFile.txt");
RestAssured.baseURI = "MY URL";
Response r = (Response)given().contentType("application/json").body(postData).when().post("");
String responseBody = r.getBody().asString();
String curlResponse = //I am providing expected Curl response here
//JSON Assertion for matching Expected and Actual response
JSONAssert.assertEquals(curlResponse, responseBody, false);
}
Also sometime we may want to avoid comparing particular field from JSON like some ID field which generate dynamically which we can do using JSON comparator
I am a fan of JSONAssert as this provides easy comparing of complete JSONs.
Just use .extract().response().getBody().asString() to get the string representation of the answer.
Complete example:
#Test
public void getReturnsExpectedDataForMailExampleCom() throws JSONException {
String response = get("/users/mail#example.com")
.then()
.statusCode(200)
.extract().response().getBody().asString();
JSONAssert.assertEquals(
"{\"email\":\"mail#example.com\",\"locale\":\"de-DE\"}",
response,
false);
}
Update The drawback is that the complete JSON is not output to stdout if the assertion fails.
I am using the java speech recognition API - Jarvis located at https://github.com/lkuza2/java-speech-api
However when I run my application, I get an error : Server returned HTTP response code: 400 for URL: https://www.google.com/speech-api/v1/recognize?xjerr=1&client=chromium&lang=en-US&maxresults=1 (This is the URL that this api uses to get response from Google)
I also created a API key as mentioned in the earlier posts and tried to use the url (this is version 2 API): www.google.com/speech-api/v2/recognize?output=json&lang=en-US&key=MYKey". But in this case I get a null response from Google.
Can anybody please tell me how to get around this?
I change some things from the Recognizer class:
I change the GOOGLE_RECOGNIZER_URL constant to:
private static final String GOOGLE_RECOGNIZER_URL = "https://www.google.com/speech-api/v2/recognize?output=json&lang=en-us&key=YOUR_KEY";
Then I changed this method because the response data have 2 lines
private String rawRequest(File inputFile, int maxResults, int sampleRate) throws IOException
The first line (the one that is read and sent) is null (i don¡t really know why) and the second line has the response of the speech recognized. For this you must read the second line (don't know if there is a nicer way):
String response = br.readLine();
response = br.readLine();
br.close();
return response;
Then I change this method, I think it was using the v1 URL response or something because this method looks for utterance in the json response and there is none utterance key.
private void parseResponse(String rawResponse, GoogleResponse googleResponse)
if (rawResponse == null)
return;
JSONObject jsonObject = new JSONObject(rawResponse);
JSONArray jsonArray= (JSONArray) jsonObject.get("result");
JSONArray jsonArrayResult = (JSONArray) jsonArray.getJSONObject(0).get("alternative");
googleResponse.setResponse(jsonArrayResult.getJSONObject(0).get("transcript").toString());
googleResponse.setConfidence(jsonArrayResult.getJSONObject(0).get("confidence").toString());
I'm new with the json library so it might be a better and shorter way but this worked for me!
Here is the message schema:>
message ServerResponse {
optional string ReferenceCode = 1;
optional NestedMessageProto.NestedMessage NestedMessage = 2;//Huge size data in response
optional bool Success = 3 [default = false];
repeated Errors Errors = 4;
}
Below is code for getting the response from serve and calling the proto response method.
String apiResponse = Server Response
protoResponseClass.parseFrom(apiResponse.getBytes())
its failing when reading the NestedMessage response on below bold line
public int pushLimit(int byteLimit) throws InvalidProtocolBufferException {
if (byteLimit < 0) {
throw InvalidProtocolBufferException.negativeSize();
}
byteLimit += totalBytesRetired + bufferPos;
if (byteLimit > currentLimit) {
currentLimit = byteLimit + currentLimit;
}
final int oldLimit = currentLimit;
**if (byteLimit > oldLimit) {
throw InvalidProtocolBufferException.truncatedMessage();
}**
currentLimit = byteLimit;
recomputeBufferSizeAfterLimit();
return oldLimit;
}
When its reading nested message the byte limit becoming greater than old limit.
What could be the solution?
Thanks
This is almost certainly the problem:
String apiResponse = Server Response
protoResponseClass.parseFrom(apiResponse.getBytes())
Protocol buffer messages are binary data. They're not text, and shouldn't be handled as text. You're taking the binary response from the server, interpreting it as text in some way (we can't tell how), then converting it back to a byte array using the platform default encoding (which is almost always a bad idea - never call getBytes() without specifying a charset, even when calling getBytes() is appropriate, which it's not here). The conversion to text and back is almost certainly losing information - quite possibly making the parsing code expect more data than is actually present in the message.
You should be handling the server response as binary data from the start - ideally just passing an InputStream from the server response into parseFrom, but at least reading it as a byte array instead of a String.
Instead of converting httpresponse to string and then to byte array for parsing, use EntityUtils.toByteArray directly.
private String readResponse(HttpResponse httpresponse) throws IOException {
int responseCode = httpresponse.getStatusLine().getStatusCode();
String mimeType = httpresponse.getFirstHeader(CONTENT_TYPE_KEY).getValue();
if (responseCode != HttpURLConnection.HTTP_OK) {
String cause = String.format("Bad HTTP response code: %d\nOr MIME type: %s", responseCode, mimeType);
throw new IOException(cause);
}
return EntityUtils.toString(httpresponse.getEntity());
}
String response = javax.swing.JOptionPane.showInputDialog("Enter new database name:");
This throws a null pointer error if the user x's out of the optionpane
Firstly, why can't response hold a null value?
secondly, how do i handle this?
full code:
String response = javax.swing.JOptionPane.showInputDialog("Enter new database name:").trim() + ".xml";
if(response != null){
File newData = new File("src\\golfdatabase\\Databases\\" + response);
try {
newData.createNewFile();
databaseComboBox.addItem(response);
} catch (IOException ex) {
Logger.getLogger(GolfDriver.class.getName()).log(Level.SEVERE, null, ex);
}
databaseComboBox.setSelectedItem(response);
disableButtonsNullList(false);
}
You have to check the return value for null and then invoke the method trim
String response = javax.swing.JOptionPane.showInputDialog("Enter new database name:");
if(response!=null)
response = response.trim()+".xml";
It gives null back when you click on "Cancel" try something like that:
String response = javax.swing.JOptionPane.showInputDialog("Enter new database name:");
if(response != null){
response = response.trim() + ".xml";
}
Take note that: String response = JOptionPane.showInputDialog(....);
Would have been enough to create the JOptionPane.
Firstly: Yes responses CAN hold a null value, but your code snippet does not show how you handle the responses so there is no way for me to tell why it is throwing them.
Secondly: That again depends on how you are handling the responses, please elaborate more on your code.
EDIT: try adding a String cast as the java tutorial suggests you do:
http://docs.oracle.com/javase/tutorial/uiswing/components/dialog.html
EDIT2: While Octopus found the problem in a piece of code (that I shamefully overlooked) please keep in mind the above points because they still hold true.
I'm coming from this question.
The following code does not work well:
public static void main(String[] args) throws Exception {
for (int i = 0; i < 15; i++)
{
String google = "http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=";
String search = "test";
String charset = "UTF-8";
URL url = new URL(google + URLEncoder.encode(search, charset));
Reader reader = new InputStreamReader(url.openStream(), charset);
GoogleResults results = new Gson().fromJson(reader, GoogleResults.class);
// Show title and URL of 1st result.
System.out.println(results.getResponseData().getResults().get(0).getTitle());
System.out.println(results.getResponseData().getResults().get(0).getUrl());
}
}
The search query works fine if I run it one time, however in this loop I get a null pointer exception.
Unfortunately I need my program to make several queries :( What can I do?
It returns a NullPointerException at the first results.getResponseData.
This is happening because Google actively blocks suspected terms of service abuse. See section 5.3 here:
http://www.google.com/accounts/TOS
If Google detects that you are issuing search requests via a program without their consent, they don't send back results. Your JSON response will contain this:
{"responseData": null, "responseDetails": "Suspected Terms of Service Abuse. Please see http://code.google.com/apis/errors", "responseStatus": 403}
Check to make sure results and other contained objects are not null before you use them.
if ((results != null) && (results.getResponseData() != null) &&
(results.getResponseData().getResults() != null) &&
(results.getResponseData().getResults().get(0) != null)) {
// Show title and URL of 1st result.
System.out.println(results.getResponseData().getResults().get(0).getTitle());
System.out.println(results.getResponseData().getResults().get(0).getUrl());
}