Skip to content

Commit

Permalink
Merge pull request #1796 from akto-api-security/feature/purge_nashorn
Browse files Browse the repository at this point in the history
remove nashorn
  • Loading branch information
notshivansh authored Dec 3, 2024
2 parents 212ed91 + 163210e commit 30c39a0
Show file tree
Hide file tree
Showing 7 changed files with 2 additions and 259 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,6 @@ const RequestEditor = ({sampleApiCall, updatedSampleData, onChangeApiRequest, te
</div>
</div>
</div>
<Divider style={{marginTop: "12px"}}></Divider>
<div style={{paddingTop: "12px"}}>
<div className="request-title">Test Validator Code</div>
<div className="request-editor request-editor-payload">
<TemplateStringEditor usePureJs={true} defaultText={testValidatorCode} onChange={onChangeTestValidatorCode}/>
</div>
</div>
<div style={{minHeight: "24px"}}></div>
</div>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,6 @@ const RequestEditor = ({sampleApiCall, updatedSampleData, onChangeApiRequest, te
</div>
</div>
</div>
<Divider style={{marginTop: "12px"}}></Divider>
<div style={{paddingTop: "12px"}}>
<div className="request-title">Test Validator Code</div>
<div className="request-editor request-editor-payload">
<TemplateStringEditor usePureJs={true} defaultText={testValidatorCode} onChange={onChangeTestValidatorCode}/>
</div>
</div>
<div style={{minHeight: "24px"}}></div>
</div>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,6 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

import com.akto.dto.ApiInfo;
import com.akto.dto.testing.*;
import com.akto.test_editor.execution.Memory;
import org.apache.commons.lang3.StringUtils;
Expand Down Expand Up @@ -501,31 +496,7 @@ public static OriginalHttpRequest buildHttpRequest(WorkflowUpdatedSampleData upd


public static String executeCode(String ogPayload, Map<String, Object> valuesMap) throws Exception {
ScriptEngineManager factory = new ScriptEngineManager();
String variablesReplacedPayload = replaceVariables(ogPayload,valuesMap, true);

String regex = "\\#\\[(.*?)]#";
Pattern p = Pattern.compile(regex);
Matcher matcher = p.matcher(variablesReplacedPayload);
StringBuffer sb = new StringBuffer();

// create a Nashorn script engine
ScriptEngine engine = factory.getEngineByName("nashorn");

while (matcher.find()) {
String code = matcher.group(1);
code = code.trim();
if (!code.endsWith(";")) code = code+";";
try {
Object val = engine.eval(code);
matcher.appendReplacement(sb, val.toString());
} catch (final ScriptException se) {
}

}

matcher.appendTail(sb);
return sb.toString();
return replaceVariables(ogPayload,valuesMap, true);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,12 @@
import com.akto.MongoBasedTest;
import com.akto.dao.OtpTestDataDao;
import com.akto.dao.context.Context;
import com.akto.dao.testing.LoginFlowStepsDao;
import com.akto.dto.OriginalHttpRequest;
import com.akto.dto.api_workflow.Node;
import com.akto.dto.testing.LoginFlowParams;
import com.akto.dto.testing.LoginFlowStepsData;
import com.akto.dto.testing.WorkflowNodeDetails;
import com.akto.dto.testing.WorkflowUpdatedSampleData;
import com.akto.dto.testing.WorkflowTestResult.NodeResult;
import com.akto.dto.type.RequestTemplate;
import com.akto.log.LoggerMaker.LogDb;
import com.akto.runtime.URLAggregator;
import com.akto.types.BasicDBListL;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.client.model.Filters;
Expand All @@ -25,14 +19,10 @@

import java.util.*;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

import static org.junit.Assert.*;

public class ApiWorkflowExecutorTest extends MongoBasedTest {


@Test
public void testCombineQueryParams2() {
String query1 = "";
Expand All @@ -41,39 +31,6 @@ public void testCombineQueryParams2() {
assertEquals("blah", combinedQuery);
}

@Test
public void testExecuteCode() throws Exception {
ApiWorkflowExecutor apiWorkflowExecutor = new ApiWorkflowExecutor();
Map<String, Object> valuesMap = new HashMap<>();
valuesMap.put("x1.response.body.user.name", "avneesh");
valuesMap.put("x1.response.body.user.age", 99);

String payload = "{\"user_name\": \"${x1.response.body.user.name}\", \"user_age\": ${x1.response.body.user.age}}";
String result = com.akto.testing.workflow_node_executor.Utils.executeCode(payload, valuesMap);
assertEquals("{\"user_name\": \"avneesh\", \"user_age\": 99}", result);


payload = "{\"user_name\": '#[\"${x1.response.body.user.name}\".toUpperCase()]#', \"user_age\": #[${x1.response.body.user.age} + 1]#}";
result = com.akto.testing.workflow_node_executor.Utils.executeCode(payload, valuesMap);
assertEquals("{\"user_name\": 'AVNEESH', \"user_age\": 100}", result);

valuesMap.put("x1.response.body.url", "https://api.razorpay.com:443/v1/payments/pay_K6FMfsnyloigxs/callback/941349c12d0e001436ace03ee711367413b176bb/rzp_test_1DP5mmOlF5G5ag");

String urlPayload = "#[ var a = '${x1.response.body.url}'; var b = a.split('/'); b[5] = 'avneesh'; b.join('/'); ]#";
result = com.akto.testing.workflow_node_executor.Utils.executeCode(urlPayload, valuesMap);
assertEquals("https://api.razorpay.com:443/v1/payments/avneesh/callback/941349c12d0e001436ace03ee711367413b176bb/rzp_test_1DP5mmOlF5G5ag", result);

urlPayload = "#[ '${x1.response.body.url}'.replace(new RegExp('pay_.*?/'), 'avneesh/') ]#";
result = com.akto.testing.workflow_node_executor.Utils.executeCode(urlPayload, valuesMap);
assertEquals("https://api.razorpay.com:443/v1/payments/avneesh/callback/941349c12d0e001436ace03ee711367413b176bb/rzp_test_1DP5mmOlF5G5ag", result);

valuesMap.put("x2.response.body.sentence", "This is sentence with a 'random' quote");
payload = "#[ '${x2.response.body.sentence}'.replace(new RegExp('random'), 'avneesh') ]#";
result = com.akto.testing.workflow_node_executor.Utils.executeCode(payload, valuesMap);
assertEquals("This is sentence with a 'avneesh' quote", result);

}

@Test
public void testPopulateValuesMap() {
ApiWorkflowExecutor apiWorkflowExecutor = new ApiWorkflowExecutor();
Expand Down Expand Up @@ -131,56 +88,6 @@ public void testBuildHttpRequest() throws Exception {
assertEquals(originalHttpRequest.getUrl(), "https://stud.akto.io/stud_10");
}


@Test
public void testValidateTest() {
ScriptEngineManager factory = new ScriptEngineManager();
ApiWorkflowExecutor apiWorkflowExecutor = new ApiWorkflowExecutor();
Map<String, Object> valuesMap = new HashMap<>();

String testValidatorCode = "${x1.response.status_code} === 200";
valuesMap.put("x1.response.status_code", 401);
boolean vulnerable = validateTest(testValidatorCode, valuesMap);
assertTrue(vulnerable);

testValidatorCode = "'${x1.request.body.user_name}' === '${x1.response.body.user_name}'";
valuesMap.put("x1.request.body.user_name", "Avneesh");
valuesMap.put("x1.response.body.user_name", "Ankush");
vulnerable = validateTest(testValidatorCode, valuesMap);
assertTrue(vulnerable);

testValidatorCode = "'${x1.request.body.CTO}' === 'Ankush'";
valuesMap.put("x1.request.body.CTO", "Ankush");
vulnerable = validateTest(testValidatorCode, valuesMap);
assertFalse(vulnerable);

String p = "<!doctype html><html style=\"height:100%\"><head><title>Razorpay - Payment in progress</title> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\"> <meta charset=\"utf-8\"> <meta http-equiv=\"Content-Type\" content=\"text/html;charset=UTF-8\"><style> body{background:#fff;font-family:ubuntu,helvetica,verdana,sans-serif;margin:0;padding:0;width:100%;height:100%;text-align:center;display:table} #text{vertical-align: middle; display: none; text-transform: uppercase; font-weight: bold; font-size: 30px; line-height: 40px} #icon{font-size: 60px;color: #fff; border-radius: 50%; width: 80px; height: 80px; line-height: 80px; margin: -60px auto 20px; display: inline-block} #text.show{display:table-cell} #text.s{color:#61BC6D;} #text.s #icon{background:#61BC6D} #text.f{color:#EF6050;} #text.f #icon{background:#EF6050} #delayed-prompt {position: fixed; top:70%; left: 0; right: 0;} .text {transition: 0.2s opacity; position: absolute; top: 0; width: 100%; opacity: 0; transition-delay: 0.2s;} .show-early .early, .show-late .late {opacity: 1} .show-early .late, .show-late .early {opacity: 0} #proceed-btn {color: #528ff0; text-decoration: underline; cursor: pointer; -webkit-tap-highlight-color: transparent;} </style> <meta name=\"viewport\" content=\"user-scalable=no,width=device-width,initial-scale=1,maximum-scale=1\"> </head><body> <div id=\"text\"><div id=\"icon\"></div><br>Payment<br> </div> <div id=\"delayed-prompt\"> <div class=\"early text\">Redirecting...</div> <div class=\"late text\" id=\"proceed-btn\">Click here to proceed</div> </div> <script> // Callback data // var data = {\"error\":{\"code\":\"BAD_REQUEST_ERROR\",\"description\":\"Payment failed\",\"source\":\"gateway\",\"step\":\"payment_authorization\",\"reason\":\"payment_failed\",\"metadata\":{\"payment_id\":\"pay_KCyZAQ3s1TQDHq\"}},\"http_status_code\":400}; // Callback data // var s = 'razorpay_payment_id' in data; data = JSON.stringify(data); if (window.CheckoutBridge) { if (typeof CheckoutBridge.oncomplete == 'function') { function onComplete() { CheckoutBridge.oncomplete(data); } setTimeout(onComplete, 30); setTimeout(function () { g('delayed-prompt').classList.add('show-early'); }, 500); setTimeout(function () { g('delayed-prompt').classList.add('show-late'); g('delayed-prompt').classList.remove('show-early'); }, 2000); g('proceed-btn').onclick = onComplete; } } else { document.cookie = 'onComplete=' + data + ';expires=Fri, 31 Dec 9999 23:59:59 GMT;path=/'; try { localStorage.setItem('onComplete', data); } catch (e) {} } var iosCheckoutBridgeNew = ((window.webkit || {}).messageHandlers || {}) .CheckoutBridge; if (iosCheckoutBridgeNew) { iosCheckoutBridgeNew.postMessage({ action: 'success', body: JSON.parse(data) }); } function g(id) { return document.getElementById(id); } function razorpay_callback() { return data; } var t = g('text'); t.innerHTML += s ? 'Successful' : 'Failed'; t.className = 'show ' + (s ? 's' : 'f'); g('icon').innerHTML = s ? '&#10004' : '!'; if (!window.CheckoutBridge) { try { window.opener.onComplete(data) } catch(e){} try { (window.opener || window.parent).postMessage(data, '*') } catch(e){} setTimeout(close, 999); } </script></body></html>";
testValidatorCode = "'${x1.response.body}'.indexOf('\"error\"') < 0";
valuesMap.put("x1.response.body", p);
vulnerable = validateTest(testValidatorCode, valuesMap);
assertTrue(vulnerable);
}

public boolean validateTest(String testValidatorCode, Map<String, Object> valuesMap) {
ScriptEngineManager factory = new ScriptEngineManager();
if (testValidatorCode == null) return false;
testValidatorCode = testValidatorCode.trim();

boolean vulnerable = false;
if (testValidatorCode.length() == 0) return false;

ScriptEngine engine = factory.getEngineByName("nashorn");
try {
String code = com.akto.testing.workflow_node_executor.Utils.replaceVariables(testValidatorCode, valuesMap, true);
Object o = engine.eval(code);
vulnerable = ! (boolean) o;
} catch (Exception e) {
;
}

return vulnerable;
}

private BasicDBObject generateValue(String host, String endpoint, String method) {
BasicDBObject value = new BasicDBObject();
value.put("host", host);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.akto.dto.testing;

import com.akto.dto.HttpRequestParams;
import com.akto.dto.OriginalHttpRequest;
import org.junit.Test;

Expand Down Expand Up @@ -28,7 +27,6 @@ private void validate(OriginalHttpRequest request, String key, List<String> modi

private void validateBodyAuthOperations(OriginalHttpRequest request, String key, String modifiedValue, String removeExpectedValue, Boolean modified, Boolean hardcoded) {
String value = "Value";
String finalKey = key.toLowerCase().trim();
AuthMechanism authMechanism = new AuthMechanism();
if (hardcoded) {
authMechanism.setAuthParams(Collections.singletonList(new HardcodedAuthParam(AuthParam.Location.BODY, key, value, false)));
Expand Down
75 changes: 0 additions & 75 deletions libs/utils/src/main/java/com/akto/testing/ApiExecutor.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.akto.dao.context.Context;
import com.akto.dao.test_editor.TestEditorEnums;
import com.akto.dao.testing.config.TestScriptsDao;
import com.akto.dto.OriginalHttpRequest;
import com.akto.dto.OriginalHttpResponse;
import com.akto.dto.CollectionConditions.ConditionsType;
Expand All @@ -28,13 +27,6 @@
import java.net.URISyntaxException;
import java.net.URL;
import java.util.*;
import java.util.concurrent.locks.Condition;

import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.SimpleScriptContext;
import jdk.nashorn.api.scripting.ScriptObjectMirror;

public class ApiExecutor {
private static final LoggerMaker loggerMaker = new LoggerMaker(ApiExecutor.class);
Expand Down Expand Up @@ -422,73 +414,6 @@ private static void calculateFinalRequestFromAdvancedSettings(OriginalHttpReques
);
}

private static void calculateHashAndAddAuth(OriginalHttpRequest originalHttpRequest, boolean executeScript) {
if (!executeScript) {
return;
}
int accountId = Context.accountId.get();
try {
String script;
TestScript testScript = testScriptMap.getOrDefault(accountId, null);
int lastTestScriptFetched = lastFetchedMap.getOrDefault(accountId, 0);
if (Context.now() - lastTestScriptFetched > 5 * 60) {
testScript = TestScriptsDao.instance.fetchTestScript();
lastTestScriptFetched = Context.now();
testScriptMap.put(accountId, testScript);
lastFetchedMap.put(accountId, Context.now());
}
if (testScript != null && testScript.getJavascript() != null) {
script = testScript.getJavascript();
} else {
// loggerMaker.infoAndAddToDb("returning from calculateHashAndAddAuth, no test script present");
return;
}
loggerMaker.infoAndAddToDb("Starting calculateHashAndAddAuth");

ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("nashorn");

SimpleScriptContext sctx = ((SimpleScriptContext) engine.get("context"));
sctx.setAttribute("method", originalHttpRequest.getMethod(), ScriptContext.ENGINE_SCOPE);
sctx.setAttribute("headers", originalHttpRequest.getHeaders(), ScriptContext.ENGINE_SCOPE);
sctx.setAttribute("url", originalHttpRequest.getPath(), ScriptContext.ENGINE_SCOPE);
sctx.setAttribute("payload", originalHttpRequest.getBody(), ScriptContext.ENGINE_SCOPE);
sctx.setAttribute("queryParams", originalHttpRequest.getQueryParams(), ScriptContext.ENGINE_SCOPE);
engine.eval(script);

String method = (String) sctx.getAttribute("method");
Map<String, Object> headers = (Map) sctx.getAttribute("headers");
String url = (String) sctx.getAttribute("url");
String payload = (String) sctx.getAttribute("payload");
String queryParams = (String) sctx.getAttribute("queryParams");

Map<String, List<String>> hs = new HashMap<>();
for (String key: headers.keySet()) {
try {
ScriptObjectMirror scm = ((ScriptObjectMirror) headers.get(key));
List<String> val = new ArrayList<>();
for (int i = 0; i < scm.size(); i++) {
val.add((String) scm.get(Integer.toString(i)));
}
hs.put(key, val);
} catch (Exception e) {
hs.put(key, (List) headers.get(key));
}
}

originalHttpRequest.setBody(payload);
originalHttpRequest.setMethod(method);
originalHttpRequest.setUrl(url);
originalHttpRequest.setHeaders(hs);
originalHttpRequest.setQueryParams(queryParams);

} catch (Exception e) {
loggerMaker.errorAndAddToDb("error in calculateHashAndAddAuth " + e.getMessage() + " url " + originalHttpRequest.getUrl());
e.printStackTrace();
return;
}
}

private static OriginalHttpResponse sendWithRequestBody(OriginalHttpRequest request, Request.Builder builder, boolean followRedirects, boolean debug, List<TestingRunResult.TestLog> testLogs, boolean skipSSRFCheck, String requestProtocol) throws Exception {
Map<String,List<String>> headers = request.getHeaders();
if (headers == null) {
Expand Down
46 changes: 1 addition & 45 deletions libs/utils/src/main/java/com/akto/testing/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

import com.akto.dto.ApiInfo.ApiInfoKey;
import com.akto.dto.CollectionConditions.ConditionsType;
import com.akto.dto.OriginalHttpRequest;
Expand Down Expand Up @@ -187,36 +183,10 @@ public static OriginalHttpRequest buildHttpRequest(WorkflowUpdatedSampleData upd
return request;
}

private static final ScriptEngineManager factory = new ScriptEngineManager();

public static String executeCode(String ogPayload, Map<String, Object> valuesMap) throws Exception {
String variablesReplacedPayload = replaceVariables(ogPayload,valuesMap, true);

String regex = "\\#\\[(.*?)]#";
Pattern p = Pattern.compile(regex);
Matcher matcher = p.matcher(variablesReplacedPayload);
StringBuffer sb = new StringBuffer();

// create a Nashorn script engine
ScriptEngine engine = factory.getEngineByName("nashorn");

while (matcher.find()) {
String code = matcher.group(1);
code = code.trim();
if (!code.endsWith(";")) code = code+";";
try {
Object val = engine.eval(code);
matcher.appendReplacement(sb, val.toString());
} catch (final ScriptException se) {
}

}

matcher.appendTail(sb);
return sb.toString();
return replaceVariables(ogPayload,valuesMap, true);
}


public static String replaceVariables(String payload, Map<String, Object> valuesMap, boolean escapeString) throws Exception {
String regex = "\\$\\{((x|step)\\d+\\.[\\w\\-\\[\\].]+|AKTO\\.changes_info\\..*?)\\}";
Pattern p = Pattern.compile(regex);
Expand Down Expand Up @@ -259,20 +229,6 @@ public static boolean validateTest(String testValidatorCode, Map<String, Object>
boolean vulnerable = false;
if (testValidatorCode.length() == 0) return false;

ScriptEngine engine = factory.getEngineByName("nashorn");
try {
String code = replaceVariables(testValidatorCode, valuesMap, true);
loggerMaker.infoAndAddToDb("*******************************************************************", LogDb.TESTING);
loggerMaker.infoAndAddToDb("TEST VALIDATOR CODE:", LogDb.TESTING);
loggerMaker.infoAndAddToDb(code, LogDb.TESTING);
Object o = engine.eval(code);
loggerMaker.infoAndAddToDb("TEST VALIDATOR RESULT: " + o.toString(), LogDb.TESTING);
loggerMaker.infoAndAddToDb("*******************************************************************", LogDb.TESTING);
vulnerable = ! (boolean) o;
} catch (Exception e) {
;
}

return vulnerable;
}

Expand Down

0 comments on commit 30c39a0

Please sign in to comment.