Skip to content

Commit 5380603

Browse files
authored
Changed neptune queries to use parameters
when able to prevent open cypher query injection. Added placeholder function for sanitization of query text that cannot be parameterized (such as node and edge labels in match clause). Sanitization logic is still to be determined after consultation with AWS.
1 parent fd0a4fc commit 5380603

File tree

1 file changed

+40
-18
lines changed

1 file changed

+40
-18
lines changed

src/NeptuneSchema.js

+40-18
Original file line numberDiff line numberDiff line change
@@ -57,34 +57,54 @@ function consoleOut(text) {
5757
}
5858
}
5959

60+
function sanitize(text) {
61+
// TODO implement sanitization logic
62+
// placeholder for sanitization of query text that cannot be parameterized
63+
return text;
64+
}
6065

61-
async function queryNeptune(q) {
66+
/**
67+
* Executes a neptune query
68+
* @param query the query to execute
69+
* @param params optional query params
70+
* @returns {Promise<ExecuteOpenCypherQueryCommandOutput|any>}
71+
*/
72+
async function queryNeptune(query, params = {}) {
6273
if (useSDK) {
63-
const response = await queryNeptuneSDK(q);
64-
return response;
74+
const response = await queryNeptuneSDK(query, params);
75+
return response;
6576
} else {
66-
try {
67-
const response = await axios.post(`https://${HOST}:${PORT}/${language}`, `query=${encodeURIComponent(q)}`);
68-
return response.data;
77+
try {
78+
let data = {
79+
query: query,
80+
parameters: JSON.stringify(params)
81+
};
82+
const response = await axios.post(`https://${HOST}:${PORT}/${language}`, data, {
83+
headers: {
84+
'Content-Type': 'application/json'
85+
}
86+
});
87+
return response.data;
6988
} catch (error) {
7089
console.error("Http query request failed: ", error.message);
71-
consoleOut("Trying with the AWS SDK");
72-
const response = await queryNeptuneSDK(q);
90+
consoleOut("Trying with the AWS SDK");
91+
const response = await queryNeptuneSDK(query, params);
7392
useSDK = true;
74-
return response;
93+
return response;
7594
}
7695
}
7796
}
7897

7998

80-
async function queryNeptuneSDK(q) {
99+
async function queryNeptuneSDK(query, params = {}) {
81100
try {
82101
const config = {
83102
endpoint: `https://${HOST}:${PORT}`
84103
};
85104
const client = new NeptunedataClient(config);
86105
const input = {
87-
openCypherQuery: q
106+
openCypherQuery: query,
107+
parameters: JSON.stringify(params)
88108
};
89109
const command = new ExecuteOpenCypherQueryCommand(input);
90110
const response = await client.send(command);
@@ -133,7 +153,7 @@ async function getEdgesNames() {
133153

134154

135155
async function findFromAndToLabels(edgeStructure) {
136-
let query = `MATCH (from)-[r:${edgeStructure.label}]->(to) RETURN DISTINCT labels(from) as fromLabel, labels(to) as toLabel`;
156+
let query = `MATCH (from)-[r:${sanitize(edgeStructure.label)}]->(to) RETURN DISTINCT labels(from) as fromLabel, labels(to) as toLabel`;
137157
let response = await queryNeptune(query);
138158
for (let result of response.results) {
139159
for (let fromLabel of result.fromLabel) {
@@ -190,9 +210,10 @@ function addUpdateEdgeProperty(edgeName, name, value) {
190210

191211

192212
async function getEdgeProperties(edge) {
193-
let query = `MATCH ()-[n:${edge.label}]->() RETURN properties(n) as properties LIMIT ${SAMPLE}`;
213+
let query = `MATCH ()-[n:${sanitize(edge.label)}]->() RETURN properties(n) as properties LIMIT $sample`;
214+
let parameters = {sample: SAMPLE};
194215
try {
195-
let response = await queryNeptune(query);
216+
let response = await queryNeptune(query, parameters);
196217
let result = response.results;
197218
result.forEach(e => {
198219
Object.keys(e.properties).forEach(key => {
@@ -214,9 +235,10 @@ async function getEdgesProperties() {
214235

215236

216237
async function getNodeProperties(node) {
217-
let query = `MATCH (n:${node.label}) RETURN properties(n) as properties LIMIT ${SAMPLE}`;
238+
let query = `MATCH (n:${sanitize(node.label)}) RETURN properties(n) as properties LIMIT $sample`;
239+
let parameters = {sample: SAMPLE};
218240
try {
219-
let response = await queryNeptune(query);
241+
let response = await queryNeptune(query, parameters);
220242
let result = response.results;
221243
result.forEach(e => {
222244
Object.keys(e.properties).forEach(key => {
@@ -238,10 +260,10 @@ async function getNodesProperties() {
238260

239261

240262
async function checkEdgeDirectionCardinality(d) {
241-
let queryFrom = `MATCH (from:${d.from})-[r:${d.edge.label}]->(to:${d.to}) WITH to, count(from) as rels WHERE rels > 1 RETURN rels LIMIT 1`;
263+
let queryFrom = `MATCH (from:${sanitize(d.from)})-[r:${sanitize(d.edge.label)}]->(to:${sanitize(d.to)}) WITH to, count(from) as rels WHERE rels > 1 RETURN rels LIMIT 1`;
242264
let responseFrom = await queryNeptune(queryFrom);
243265
let resultFrom = responseFrom.results[0];
244-
let queryTo = `MATCH (from:${d.from})-[r:${d.edge.label}]->(to:${d.to}) WITH from, count(to) as rels WHERE rels > 1 RETURN rels LIMIT 1`;
266+
let queryTo = `MATCH (from:${sanitize(d.from)})-[r:${sanitize(d.edge.label)}]->(to:${sanitize(d.to)}) WITH from, count(to) as rels WHERE rels > 1 RETURN rels LIMIT 1`;
245267
let responseTo = await queryNeptune(queryTo);
246268
let resultTo = responseTo.results[0];
247269
let c = '';

0 commit comments

Comments
 (0)