I am getting a high severity issue in this method:
public void recordBadLogin(final String uid, final String reason, final String ip) throws DataAccessException {
if (Utils.isEmpty(uid)) {
throw new DataAccessException("User information needed to update , Empty user information passed");
}
try {
String sql = (String) this.queries.get(IUtilDAO.queryKeyPrefix + UtilDAO.RECORD_FAILED_LOGIN);
Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put("uid", uid.trim());
paramMap.put("reason", (reason != null ? reason.trim() : "Invalid userid/password"));
paramMap.put("ip", ip);
this.namedJdbcTemplate.update(sql, paramMap);
} catch (Exception e) {
throw new DataAccessException("Failed to record bad login for user " + uid, e);
}
}
This line of code is causing the issue:
String sql = (String) this.queries.get(IUtilDAO.queryKeyPrefix + UtilDAO.RECORD_FAILED_LOGIN);
queries is a properties object and the prepared statement is being retrieved given IUtilDAO.queryKeyPrefix + UtilDAO.RECORD_FAILED_LOGIN. And those 2 arguments are constants. Logically I don't see how this can cause an SQL injection issue as the prepared statement is being retrieved from a dictionary. Does anyone have an idea if this is a false positive or if there is an actual vulnerability present?
It's hard to tell from the example given, but I'd guess that the properties object was tainted by untrusted data. Most code flow analysis tools will taint the entire data structure if any untrusted data is placed in it.
Technically this is a "false positive". But architecturally it's something that should be fixed - it's generally a bad idea to mix trusted and untrusted data together in the same data structure. It makes it easy for future developers to misunderstand the status of a particular element, and makes it harder for both humans and tools to code review for security issues.
Related
I am newbie to MongoDB i implemented transactional feature in one of my application, as per my requirements i need to persist data into different collections in the same database. Below is the code snippet for the same
In Tuple3 first element is database, second element is collection and third element is data i want to persist which is coming as json string which i am converting to bson document
ClientSession clientSession = mongoClient.startSession();
try {
clientSession.startTransaction(transactionOptions);
for (Tuple3<String, String, String> value: insertValues) {
MongoCollection<Document> collection = mongoClient
.getDatabase(insertValues.f0)
.getCollection(insertValues.f1);
Document data= Document.parse(insertValues.f2);
log.info(String.format("Inserting data into database %s and collection is %s", insertValues.f0, insertValues.f1));
collection.insertOne(clientSession, data);
clientSession.commitTransaction();
}
} catch (MongoCommandException | MongoWriteException exception) {
clientSession.abortTransaction();
log.error(String.format("Exception happened while inserting record into Mongo DB rolling back the transaction " +
"and cause of exception is: %s", exception));
} finally {
clientSession.close();
}
Below are transaction options i am using
TransactionOptions transactionOptions = TransactionOptions.builder().readConcern(ReadConcern.LOCAL).writeConcern(WriteConcern.W1).build();
Below is MongoClient method with MongoClientOptions i am taking Mongo DB Connection string as input to this method
public MongoClient getTransactionConnection(String connectionString) {
MongoClientOptions.Builder mongoClientOptions = new MongoClientOptions.Builder()
.readConcern(ReadConcern.LOCAL)
.writeConcern(WriteConcern.W1)
.readPreference(ReadPreference.primary())
.serverSelectionTimeout(120000)
.maxWaitTime(120000)
.connectionsPerHost(10)
.connectTimeout(120000);
MongoClientURI uri = new MongoClientURI(connectionString, mongoClientOptions);
return new MongoClient(uri);
}
Till here it is good and it is inserting data to three different collection under the specified database. But when i try to some negative scenario i am trying to throw exception in try block which ideally should rollback the data for that particular client session if any error happens.
I am trying to throw exception by using count variable which will increment and for if count value is equal to 1 i am throwing exception which should abort the transaction and rollback if any data is written to database but what i am seeing it is writing to one of the collection and throws exception after that stops the program but it is not rolling back the data written to collection actually. I am trying something like this below
ClientSession clientSession = mongoClient.startSession();
int count = 0;
try {
clientSession.startTransaction(transactionOptions);
for (Tuple3<String, String, String> value: insertValues) {
MongoCollection<Document> collection = mongoClient
.getDatabase(insertValues.f0)
.getCollection(insertValues.f1);
Document data= Document.parse(insertValues.f2);
log.info(String.format("Inserting data into database %s and collection is %s", insertValues.f0, insertValues.f1));
collection.insertOne(clientSession, data);
if(count == 1){
throw new MongoException("Aborting transaction.....");
}
count++;
clientSession.commitTransaction();
}
} catch (MongoCommandException | MongoWriteException exception) {
clientSession.abortTransaction();
log.error(String.format("Exception happened while inserting record into Mongo DB rolling back the transaction " +
"and cause of exception is: %s", exception));
} finally {
clientSession.close();
}
I am not sure where i am going wrong i am using Mongo DB version 4.0 deployed using Azure CosmosDB Api. Please help me in resolving this issue thanks in advance.
Cosmos DB does not have transaction support outside of a single partition (shard) of a single collection. This limitation exists regardless of API in use (in your case, MongoDB API). This is why you're not seeing the behavior you're expecting. Note: this is mentioned in the Cosmos DB MongoDB compatibility docs.
You'll need to come up with your own implementation for managing data consistency within your app.
Apparently, in the move from Spring Boot 1 to Spring Boot 2 (Spring 5), the encoding behavior of URL parameters for RestTemplates changed. It seems unusually difficult to get a general query parameter on rest templates passed so that characters that have special meanings such as "+" get properly escaped. It seems that, since "+" is a valid character, it doesn't get escaped, even though its meaning gets altered (see here). This seems bizarre, counter-intuitive, and against every other convention on every other platform. More importantly, I can't figure out how to easily get around it. If I encode the string first, it gets double-encoded, because the "%"s get re-encoded. Anyway, this seems like it should be something very simple that the framework does, but I'm not figuring it out.
Here is my code that worked in Spring Boot 1:
String url = "https://base/url/here";
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url);
for (Map.Entry<String, String> entry : query.entrySet()) {
builder.queryParam(entry.getKey(), entry.getValue());
}
HttpEntity<TheResponse> resp = myRestTemplate.exchange(builder.toUriString(), ...);
However, now it won't encode the "+" character, so the other end is interpreting it as a space. What is the correct way to build this URL in Java Spring Boot 2?
Note - I also tried this, but it actually DOUBLE-encodes everything:
try {
for (Map.Entry<String, String> entry : query.entrySet()) {
builder.queryParam(entry.getKey(), URLEncoder.encode(entry.getValue(),"UTF-8" ));
}
} catch(Exception e) {
System.out.println("Encoding error");
}
In the first one, if I put in "q" => "abc+1#efx.com", then, exactly in the URL, I get "abc+1#efx.com" (i.e., not encoded at all). However, in the second one, if I put in "abc+1#efx.com", then I get "abc%252B1%2540efx.com", which is DOUBLE-encoded.
I could hand-write an encoding method, but this seems (a) like overkill, and (b) doing encoding yourself is where security problems and weird bugs tend to creep in. But it seems insane to me that you can't just add a query parameter in Spring Boot 2. That seems like a basic task. What am I missing?
Found what I believe to be a decent solution. It turns out that a large part of the problem is actually the "exchange" function, which takes a string for a URL, but then re-encodes that URL for reasons I cannot fathom. However, the exchange function can be sent a java.net.URI instead. In this case, it does not try to interpolate anything, as it is already a URI. I then use java.net.URLEncoder.encode() to encode the pieces. I still have no idea why this isn't standard in Spring, but this should work.
private String mapToQueryString(Map<String, String> query) {
List<String> entries = new LinkedList<String>();
for (Map.Entry<String, String> entry : query.entrySet()) {
try {
entries.add(URLEncoder.encode(entry.getKey(), "UTF-8") + "=" + URLEncoder.encode(entry.getValue(), "UTF-8"));
} catch(Exception e) {
log.error("Unable to encode string for URL: " + entry.getKey() + " / " + entry.getValue(), e);
}
}
return String.join("&", entries);
}
/* Later in the code */
String endpoint = "https://baseurl.example.com/blah";
String finalUrl = query.isEmpty() ? endpoint : endpoint + "?" + mapToQueryString(query);
URI uri;
try {
uri = new URI(finalUrl);
} catch(URISyntaxException e) {
log.error("Bad URL // " + finalUrl, e);
return null;
}
}
/* ... */
HttpEntity<TheResponse> resp = myRestTemplate.exchange(uri, ...)
For the below mentioned code, I'm getting Trust Boundary Violation in the CheckMarx report.
Error description -
Method 'getResponse' gets user input from element request. This element’s value flows through the code without being properly sanitized or validated and is eventually stored in the server-side Session object, in 'parseRequest' method.**
Code -
#Context
HttpHeaders httpHeader;
void parseRequest(SomeRequestType inputRequest) {
HashMap<String, Data> requestData = inputRequest.getRequestData(httpHeader);
if (requestData != null) {
if (Strings.isNullOrEmpty(inputRequest.getId())) {
Data data = requestData.get("data");
var dataID = data.getID();
if ((dataID != null) && Pattern.matches("[0-9]+", dataID)) {
inputRequest.setId(dataID);
ThreadContext.put("ID", dataID);
}
}
}
}
I am getting checkmarx vulnerability at below line for without being properly sanitized or validated
ThreadContext.put("ID", dataID);
Could some please help me, how to properly sanitize the above line.
If you know for sure that dataID is a number, convert it to integer/long right away, like this:
int dataIDasNumber = Integer.parseInt(dataID);
And use it like int/long here:
inputRequest.setId(dataIDasNumber);
ThreadContext.put("ID", dataIDasNumber);
Then you don't need to do this:
Pattern.matches...
And your checkmarx violation should go away.
I am using UnboundID-LDAPSDK (2.3.8) to change the user's photo in our Microsoft Active Directory.
LDAPConnection ldap = null;
try {
ldap = new LDAPConnection("domain-srv", 389, "CN=admin,OU=Users,OU=ADM,DC=domain,DC=local", "password");
SearchResult sr = ldap.search("DC=domain,DC=local", SearchScope.SUB, "(sAMAccountName=" + getUser().getUsername() + ")");
if (sr.getEntryCount() == 1) {
SearchResultEntry entry = sr.getSearchEntries().get(0);
entry.setAttribute("thumbnailPhoto", getUser().getPhotoAsByteArray());
ldap.close();
return true;
} else
return false;
} catch (LDAPException e) {
e.printStackTrace();
}
But I get a java.lang.UnsupportedOperationException.
The documentation for setAttribute states:
Throws an UnsupportedOperationException to indicate that this is a
read-only entry.
I also tried to change the postalCode but I get the same exception.
Changing those attributes should be possible, because I can change them with jXplorer.
Do I have to enable a write-mode somehow?
Thank you
The SearchResultEntry object extends ReadOnlyEntry and is therefore immutable. But even if it weren't, merely calling entry.setAttribute would have no effect on the data in the server. You have to use a modify operation for that.
To do that, you'd need something like:
ModifyRequest modifyRequest = new ModifyRequest(entry.getDN(),
new Modification(ModificationType.REPLACE,
"thumbnailPhoto", getUser().getPhotoAsByteArray());
ldap.modify(modifyRequest);
Also, you should put the call to ldap.close() in a finally block because as the code is written now, you're only closing the connection if the search is successful and returns exactly one entry, but not if the search fails, doesn't match any entries, or the attempt to perform the modify fails.
In a program I'm working on in Java where I have to read data from a file. The data is formatted so that each line contains all the necessary information to construct a new object. When I parse the data, I have a block of code that looks something like this:
String[] parts = file.nextLine().split(",");
String attr1 = parts[0];
int attr2, attr3;
try{
attr2 = Integer.parseInt(parts[1]);
} catch (NumberFormatException ex){
System.out.println("Could not parse attr2, got " + parts[1] + ".");
return;
}
try{
attr3 = Integer.parseInt(parts[2]);
} catch (NumberFormatException ex){
System.out.println("Could not parse attr3, got " + parts[2] + ".");
return;
}
ClassA attr4 = null, attr5 = null, attr6 = null;
try{
...
} catch (SomeExceptionType ex){
System.out.println("Could not parse attr4, got " + parts[3] + ".");
}
...
I find myself repeating the same simple try block over and over again. In an attempt to mitigate the situation and adhere to the DRY principle a bit more, I introduced some attempt methods:
int attr2 = attemptGetInt(parts, 1, "attr2");
int attr3 = attemptGetInt(parts, 2, "attr3");
ClassA attr4 = attemptGetClassA(parts, 3, "attr4");
...
// Somewhere in the class
public int attemptGetInt(String[] parts, int index, String name) throws SomeOtherException1{
try{
return Integer.parseInt(parts[index]);
} catch (NumberFormatException ex){
throw new SomeOtherException1("Could not parse " + name + ", got " + parts[index] + ".");
}
}
public ClassA attemptGetClassA(String[] parts, int index, String name) throws SomeOtherException2{
try{
return ...
} catch (SomeExceptionType ex){
throw new SomeOtherException2("Could not parse " + name + ", got" + parts[index] + ".");
}
}
...
Even this feels weird though, because there are a lot of different types I have to return that all sort of have the same but slightly different code and need to catch a slightly different error each time (i.e. I have to create an attemptGetClassB and attemptGetClassC and so on, a bunch of times with similar code each time).
Is there an elegant way of writing code like this?
If you have control over the format of the input file you might wish to change it to XML with a schema. That way the parser itself takes care of a lot of this type of checking for you.
However from the nature of the question I assume the format is fixed. In that case I would suggest splitting the syntax checking and parsing into separate steps for each line.
An easy way to do the syntax checking is using a regexp. Fairly complex syntax can be encoded in a regular expression so unless the files contain some sort of nesting (in which case DEFINITELY use XML instead) then it should be fairly straightforward.
The second step of parsing should then only return exceptions by exception :-) You still need to catch them but it's perfectly good form to gather all of your catches into a single block because it should only be used when debugging: in normal operations the syntax check will catch errors before this step.
My view is that this design is more intuitive and obvious. It may have a downside in error reporting if you specifically want to report on each error separately. In that case you'll need to break the string into substrings first (using a Scanner for example) and then syntax check each substring.
As a final note, opinions vary on this but my personal preference is not to use exception handling for conditions that occur in normal operations. They are not well suited for that (in my opinion). Better to do what I'm suggesting here: have explicit code to check error conditions before processing and then use exceptions for things that should not normally occur.