input validation for database connection data
This commit is contained in:
parent
1981a23b51
commit
575a7d4979
@ -44,5 +44,10 @@
|
|||||||
"database-parsing/limit-next": "Load at most",
|
"database-parsing/limit-next": "Load at most",
|
||||||
"database-parsing/limit": "row(s) of data",
|
"database-parsing/limit": "row(s) of data",
|
||||||
"database-parsing/store-row": "Store blank rows",
|
"database-parsing/store-row": "Store blank rows",
|
||||||
"database-parsing/store-cell": "Store blank cells as nulls"
|
"database-parsing/store-cell": "Store blank cells as nulls",
|
||||||
|
"database-source/alert-conn-name-invalid-character": "Connection Name Input Error: Illegal Character in Input. Only [a-zA-Z0-9._-] Allowed",
|
||||||
|
"database-source/alert-db-host-invalid-character": "Database Host Error: Illegal Character in Input. Only Alphanumeric characters allowed",
|
||||||
|
"database-source/alert-db-user-invalid-character": "Database User Error: Illegal Character in Input. Only Alphanumeric characters allowed",
|
||||||
|
"database-source/alert-db-port-invalid-character": "Database Port Error: Illegal Character in Input. Only Numeric values allowed."
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -127,11 +127,11 @@ Refine.DatabaseSourceUI.prototype.attachUI = function(body) {
|
|||||||
this._elmts.saveConnectionButton.click(function(evt) {
|
this._elmts.saveConnectionButton.click(function(evt) {
|
||||||
|
|
||||||
if(self._validateNewConnectionForm() == true){
|
if(self._validateNewConnectionForm() == true){
|
||||||
var connectionNameInput = $.trim(self._elmts.connectionNameInput[0].value);
|
var connectionNameInput = $.trim(self._elmts.connectionNameInput[0].value);
|
||||||
if (connectionNameInput.length === 0) {
|
if (connectionNameInput.length === 0) {
|
||||||
window.alert($.i18n('database-source/alert-connection-name'));
|
window.alert($.i18n('database-source/alert-connection-name'));
|
||||||
} else{
|
} else{
|
||||||
self._saveConnection(self._getConnectionInfo());
|
self._saveConnection(self._getConnectionInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -431,6 +431,9 @@ Refine.DatabaseSourceUI.prototype._getConnectionInfo = function() {
|
|||||||
var self = this;
|
var self = this;
|
||||||
var jdbcConnectionInfo = {};
|
var jdbcConnectionInfo = {};
|
||||||
jdbcConnectionInfo.connectionName = $.trim(self._elmts.connectionNameInput[0].value);
|
jdbcConnectionInfo.connectionName = $.trim(self._elmts.connectionNameInput[0].value);
|
||||||
|
|
||||||
|
// window.alert('input:' + jdbcConnectionInfo.connectionName + ' output:' + self._removeScriptTag(jdbcConnectionInfo.connectionName) );
|
||||||
|
|
||||||
jdbcConnectionInfo.databaseType = $.trim(self._elmts.databaseTypeSelect[0].value);
|
jdbcConnectionInfo.databaseType = $.trim(self._elmts.databaseTypeSelect[0].value);
|
||||||
jdbcConnectionInfo.databaseServer = $.trim(self._elmts.databaseHostInput[0].value);
|
jdbcConnectionInfo.databaseServer = $.trim(self._elmts.databaseHostInput[0].value);
|
||||||
jdbcConnectionInfo.databasePort = $.trim(self._elmts.databasePortInput[0].value);
|
jdbcConnectionInfo.databasePort = $.trim(self._elmts.databasePortInput[0].value);
|
||||||
@ -442,6 +445,18 @@ Refine.DatabaseSourceUI.prototype._getConnectionInfo = function() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Refine.DatabaseSourceUI.prototype._removeScriptTag = function(input) {
|
||||||
|
var div = document.createElement('div');
|
||||||
|
div.innerHTML = s;
|
||||||
|
var scripts = div.getElementsByTagName('script');
|
||||||
|
var i = scripts.length;
|
||||||
|
while (i--) {
|
||||||
|
scripts[i].parentNode.removeChild(scripts[i]);
|
||||||
|
}
|
||||||
|
return div.innerHTML;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
Refine.DatabaseSourceUI.prototype._validateNewConnectionForm = function() {
|
Refine.DatabaseSourceUI.prototype._validateNewConnectionForm = function() {
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
@ -454,21 +469,45 @@ Refine.DatabaseSourceUI.prototype._validateNewConnectionForm = function() {
|
|||||||
var initialDatabaseInput = $.trim(self._elmts.initialDatabaseInput[0].value);
|
var initialDatabaseInput = $.trim(self._elmts.initialDatabaseInput[0].value);
|
||||||
var initialSchemaInput = $.trim(self._elmts.initialSchemaInput[0].value);
|
var initialSchemaInput = $.trim(self._elmts.initialSchemaInput[0].value);
|
||||||
|
|
||||||
if (databaseHostInput.length === 0) {
|
var alphaNumRE = /^[a-zA-Z0-9._-]*$/;
|
||||||
|
var numRE = /^[0-9]*$/;
|
||||||
|
|
||||||
|
var alphaNumConnNameTestResult = alphaNumRE.test(connectionNameInput);
|
||||||
|
var databaseHostTestResult = alphaNumRE.test(databaseHostInput);
|
||||||
|
var databasePortTestResult = numRE.test(databasePortInput);
|
||||||
|
var databaseUserTestResult = alphaNumRE.test(databaseUserInput);
|
||||||
|
|
||||||
|
if(alphaNumConnNameTestResult == false){
|
||||||
|
window.alert($.i18n('database-source/alert-conn-name-invalid-character'));
|
||||||
|
return false;
|
||||||
|
}else if(connectionNameInput.contains("<script>") || connectionNameInput.contains("<img>")){
|
||||||
|
window.alert($.i18n('database-source/alert-conn-name-invalid-character'));
|
||||||
|
return false;
|
||||||
|
}else if (databaseHostInput.length === 0) {
|
||||||
window.alert($.i18n('database-source/alert-server'));
|
window.alert($.i18n('database-source/alert-server'));
|
||||||
return false;
|
return false;
|
||||||
|
}else if(databaseHostInput.contains("<script>") || databaseHostInput.contains("<img>")){
|
||||||
|
window.alert($.i18n('database-source/alert-db-host-invalid-character'));
|
||||||
|
return false;
|
||||||
}else if(databasePortInput.length === 0){
|
}else if(databasePortInput.length === 0){
|
||||||
window.alert($.i18n('database-source/alert-port'));
|
window.alert($.i18n('database-source/alert-port'));
|
||||||
return false;
|
return false;
|
||||||
}else if(databaseUserInput.length === 0){
|
}else if(databaseUserInput.length === 0){
|
||||||
window.alert($.i18n('database-source/alert-user'));
|
window.alert($.i18n('database-source/alert-user'));
|
||||||
return false;
|
return false;
|
||||||
|
}else if(databaseUserInput.contains("<script>") || databaseUserInput.contains("<img>")){
|
||||||
|
window.alert($.i18n('database-source/alert-db-user-invalid-character'));
|
||||||
|
return false;
|
||||||
}else if(initialDatabaseInput.length === 0){
|
}else if(initialDatabaseInput.length === 0){
|
||||||
window.alert($.i18n('database-source/alert-initial-database'));
|
window.alert($.i18n('database-source/alert-initial-database'));
|
||||||
return false;
|
return false;
|
||||||
|
}else if(databasePortTestResult == false){
|
||||||
|
window.alert($.i18n('database-source/alert-db-port-invalid-character'));
|
||||||
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,6 +167,13 @@
|
|||||||
<version>3.6</version>
|
<version>3.6</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.owasp.encoder</groupId>
|
||||||
|
<artifactId>encoder</artifactId>
|
||||||
|
<version>1.2.2</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.testng</groupId>
|
<groupId>org.testng</groupId>
|
||||||
|
@ -314,7 +314,7 @@ public class DatabaseUtils {
|
|||||||
String fileSep = System.getProperty("file.separator");
|
String fileSep = System.getProperty("file.separator");
|
||||||
String filename = dir.getPath() + fileSep + DATABASE_EXTENSION_DIR + fileSep + SETTINGS_FILE_NAME;
|
String filename = dir.getPath() + fileSep + DATABASE_EXTENSION_DIR + fileSep + SETTINGS_FILE_NAME;
|
||||||
|
|
||||||
// logger.info("** extension file name: {} **", filename);
|
logger.debug("** extension file name: {} **", filename);
|
||||||
return filename;
|
return filename;
|
||||||
}
|
}
|
||||||
public static String getExtensionFolder(){
|
public static String getExtensionFolder(){
|
||||||
|
@ -31,12 +31,15 @@ package com.google.refine.extension.database.cmd;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.apache.http.HttpStatus;
|
import org.apache.http.HttpStatus;
|
||||||
|
import org.owasp.encoder.Encode;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@ -50,6 +53,9 @@ public class SavedConnectionCommand extends DatabaseCommand {
|
|||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger("SavedConnectionCommand");
|
private static final Logger logger = LoggerFactory.getLogger("SavedConnectionCommand");
|
||||||
|
|
||||||
|
private static final Pattern CONN_NAME_PATTERN = Pattern.compile("^[a-zA-Z0-9._-]*");
|
||||||
|
private static final Pattern DATABASE_PORT_PATTERN = Pattern.compile("^[0-9]*");
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doGet(HttpServletRequest request, HttpServletResponse response)
|
public void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||||
@ -126,15 +132,23 @@ public class SavedConnectionCommand extends DatabaseCommand {
|
|||||||
writer.writeArrayFieldStart(DatabaseUtils.SAVED_CONNECTION_KEY);
|
writer.writeArrayFieldStart(DatabaseUtils.SAVED_CONNECTION_KEY);
|
||||||
|
|
||||||
writer.writeStartObject();
|
writer.writeStartObject();
|
||||||
writer.writeStringField("connectionName", savedConnection.getConnectionName());
|
|
||||||
|
String sanitizedConnName = Encode.forHtml(savedConnection.getConnectionName());
|
||||||
|
|
||||||
|
// writer.writeStringField("connectionName", savedConnection.getConnectionName());
|
||||||
|
writer.writeStringField("connectionName", sanitizedConnName);
|
||||||
|
|
||||||
writer.writeStringField("databaseType", savedConnection.getDatabaseType());
|
writer.writeStringField("databaseType", savedConnection.getDatabaseType());
|
||||||
|
|
||||||
writer.writeStringField("databaseHost", savedConnection.getDatabaseHost());
|
String sanitizedHost = Encode.forHtml(savedConnection.getDatabaseHost());
|
||||||
|
// writer.writeStringField("databaseHost", savedConnection.getDatabaseHost());
|
||||||
|
writer.writeStringField("databaseHost", sanitizedHost);
|
||||||
|
|
||||||
writer.writeNumberField("databasePort", savedConnection.getDatabasePort());
|
writer.writeNumberField("databasePort", savedConnection.getDatabasePort());
|
||||||
|
|
||||||
writer.writeStringField("databaseName", savedConnection.getDatabaseName());
|
String sanitizedDbName = Encode.forHtml(savedConnection.getDatabaseName());
|
||||||
|
// writer.writeStringField("databaseName", savedConnection.getDatabaseName());
|
||||||
|
writer.writeStringField("databaseName", sanitizedDbName);
|
||||||
|
|
||||||
String dbPasswd = savedConnection.getDatabasePassword();
|
String dbPasswd = savedConnection.getDatabasePassword();
|
||||||
if(dbPasswd != null && !dbPasswd.isEmpty()) {
|
if(dbPasswd != null && !dbPasswd.isEmpty()) {
|
||||||
@ -143,8 +157,11 @@ public class SavedConnectionCommand extends DatabaseCommand {
|
|||||||
writer.writeStringField("databasePassword", dbPasswd);
|
writer.writeStringField("databasePassword", dbPasswd);
|
||||||
|
|
||||||
writer.writeStringField("databaseSchema", savedConnection.getDatabaseSchema());
|
writer.writeStringField("databaseSchema", savedConnection.getDatabaseSchema());
|
||||||
|
String sanitizedDbUser = Encode.forHtml(savedConnection.getDatabaseUser());
|
||||||
|
// writer.writeStringField("databaseUser", savedConnection.getDatabaseUser());
|
||||||
|
writer.writeStringField("databaseUser", sanitizedDbUser);
|
||||||
|
|
||||||
writer.writeStringField("databaseUser", savedConnection.getDatabaseUser());
|
logger.info("Input DB User:{}, SanitizedDbUser:{}", savedConnection.getDatabaseUser(), sanitizedDbUser);
|
||||||
|
|
||||||
writer.writeEndObject();
|
writer.writeEndObject();
|
||||||
writer.writeEndArray();
|
writer.writeEndArray();
|
||||||
@ -229,6 +246,7 @@ public class SavedConnectionCommand extends DatabaseCommand {
|
|||||||
logger.debug("doPost Connection: {}", request.getParameter("connectionName"));
|
logger.debug("doPost Connection: {}", request.getParameter("connectionName"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DatabaseConfiguration jdbcConfig = getJdbcConfiguration(request);
|
DatabaseConfiguration jdbcConfig = getJdbcConfiguration(request);
|
||||||
|
|
||||||
|
|
||||||
@ -241,6 +259,21 @@ public class SavedConnectionCommand extends DatabaseCommand {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!validateInput(jdbcConfig.getConnectionName(), CONN_NAME_PATTERN)) {
|
||||||
|
logger.warn("Invalid Connection Name: {}", jdbcConfig.getConnectionName());
|
||||||
|
response.sendError(HttpStatus.SC_BAD_REQUEST, "Connection Name is Invalid. Expecting [a-zA-Z0-9._-]");
|
||||||
|
response.flushBuffer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!validateInput("" + jdbcConfig.getDatabasePort(), DATABASE_PORT_PATTERN)) {
|
||||||
|
logger.warn("Invalid Database Port: {}", jdbcConfig.getDatabasePort());
|
||||||
|
response.sendError(HttpStatus.SC_BAD_REQUEST, "Database Port Invalid. Expecting Numeric values only");
|
||||||
|
response.flushBuffer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
DatabaseConfiguration savedConn = DatabaseUtils.getSavedConnection(jdbcConfig.getConnectionName());
|
DatabaseConfiguration savedConn = DatabaseUtils.getSavedConnection(jdbcConfig.getConnectionName());
|
||||||
if(savedConn != null) {
|
if(savedConn != null) {
|
||||||
response.sendError(HttpStatus.SC_BAD_REQUEST, "Connection with name " + jdbcConfig.getConnectionName() + " already exists!");
|
response.sendError(HttpStatus.SC_BAD_REQUEST, "Connection with name " + jdbcConfig.getConnectionName() + " already exists!");
|
||||||
@ -267,7 +300,13 @@ public class SavedConnectionCommand extends DatabaseCommand {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean validateInput(String input, Pattern pattern){
|
||||||
|
Matcher matcher = pattern.matcher(input);
|
||||||
|
if(matcher.matches()){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doPut(HttpServletRequest request, HttpServletResponse response)
|
public void doPut(HttpServletRequest request, HttpServletResponse response)
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
package com.google.refine.extension.database.cmd;
|
package com.google.refine.extension.database.cmd;
|
||||||
|
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
import static org.testng.Assert.assertFalse;
|
||||||
|
import static org.testng.Assert.assertNotEquals;
|
||||||
|
import static org.testng.Assert.assertNotNull;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -154,8 +157,11 @@ public class SavedConnectionCommandTest extends DBExtensionTests{
|
|||||||
SUT.doPost(request, response);
|
SUT.doPost(request, response);
|
||||||
|
|
||||||
String result = sw.getBuffer().toString().trim();
|
String result = sw.getBuffer().toString().trim();
|
||||||
|
assertNotNull(result);
|
||||||
|
assertFalse(result.isEmpty(), "Valid response Message expected!");
|
||||||
|
|
||||||
ObjectNode json = ParsingUtilities.mapper.readValue(result, ObjectNode.class);
|
ObjectNode json = ParsingUtilities.mapper.readValue(result, ObjectNode.class);
|
||||||
|
System.out.println("json:" + json);
|
||||||
|
|
||||||
ArrayNode savedConnections = (ArrayNode) json.get("savedConnections");
|
ArrayNode savedConnections = (ArrayNode) json.get("savedConnections");
|
||||||
Assert.assertNotNull(savedConnections);
|
Assert.assertNotNull(savedConnections);
|
||||||
@ -229,7 +235,7 @@ public class SavedConnectionCommandTest extends DBExtensionTests{
|
|||||||
Assert.assertEquals(savedConnections.size(), 1);
|
Assert.assertEquals(savedConnections.size(), 1);
|
||||||
|
|
||||||
ObjectNode sc = (ObjectNode)savedConnections.get(0);
|
ObjectNode sc = (ObjectNode)savedConnections.get(0);
|
||||||
System.out.println("sc" + sc);
|
//System.out.println("sc" + sc);
|
||||||
String newDbHost = sc.get("databaseHost").asText();
|
String newDbHost = sc.get("databaseHost").asText();
|
||||||
Assert.assertEquals(newDbHost, newHost);
|
Assert.assertEquals(newDbHost, newHost);
|
||||||
}
|
}
|
||||||
@ -289,4 +295,43 @@ public class SavedConnectionCommandTest extends DBExtensionTests{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Added to check XSS invalid tokens
|
||||||
|
* @throws IOException
|
||||||
|
* @throws ServletException
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testDoPostInvalidConnectionName() throws IOException, ServletException {
|
||||||
|
|
||||||
|
when(request.getParameter("connectionName")).thenReturn("<img></img>");
|
||||||
|
when(request.getParameter("databaseType")).thenReturn(MySQLDatabaseService.DB_NAME);
|
||||||
|
when(request.getParameter("databaseServer")).thenReturn(testDbConfig.getDatabaseHost());
|
||||||
|
when(request.getParameter("databasePort")).thenReturn("" + testDbConfig.getDatabasePort());
|
||||||
|
when(request.getParameter("databaseUser")).thenReturn(testDbConfig.getDatabaseUser());
|
||||||
|
when(request.getParameter("databasePassword")).thenReturn(testDbConfig.getDatabasePassword());
|
||||||
|
when(request.getParameter("initialDatabase")).thenReturn(testDbConfig.getDatabaseName());
|
||||||
|
|
||||||
|
StringWriter sw = new StringWriter();
|
||||||
|
PrintWriter pw = new PrintWriter(sw);
|
||||||
|
|
||||||
|
when(response.getWriter()).thenReturn(pw);
|
||||||
|
|
||||||
|
SUT.doPost(request, response);
|
||||||
|
|
||||||
|
String result = sw.getBuffer().toString().trim();
|
||||||
|
assertNotNull(result);
|
||||||
|
assertFalse(result.isEmpty(), "Valid response Message expected!");
|
||||||
|
|
||||||
|
ObjectNode json = ParsingUtilities.mapper.readValue(result, ObjectNode.class);
|
||||||
|
System.out.println("json:" + json);
|
||||||
|
|
||||||
|
ArrayNode savedConnections = (ArrayNode) json.get("savedConnections");
|
||||||
|
Assert.assertNotNull(savedConnections);
|
||||||
|
|
||||||
|
int len = savedConnections.size();
|
||||||
|
|
||||||
|
Assert.assertEquals(len, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user