Skip to content

Throws exception when passed IP address with too long mask #7084

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

clementkng
Copy link
Contributor

@clementkng clementkng commented Jul 5, 2019

Originally, matches(String address) would first call parse on an address, when I believe the correct behavior is to first check for the validity of the subnet mask (an invalid mask for an IP address is invalid regardless of what method it's a part of). This is why invalid masks could be passed into the constructor but then throw exceptions on valid calls to matches. So I changed both the constructor and the matches method to first validate that the mask in the IP address passed in is not too long.

Draft b/c I'm not sure if my assumption fully holds for all cases.

Fixes gh-2790

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jul 5, 2019
@clementkng clementkng marked this pull request as ready for review July 5, 2019 22:38
Copy link
Contributor

@jzheaux jzheaux left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@clementkng, thanks for the PR! I left some feedback inline.

}

public boolean matches(HttpServletRequest request) {
return matches(request.getRemoteAddr());
}

public boolean matches(String address) {
InetAddress remoteAddress = parseAddress(address);
String [] addressAndMask = preprocessAddressAndMask(address);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The address passed into this method doesn't have a mask, so the preprocessing is unnecessary here.

As such, the preprocessAddressAndMask method is probably also unnecessary for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So does this mean that we don't have to check remote address anymore, since there's no mask that will be assigned there?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because of this line:

if ((remAddr[i] & mask[i]) != (reqAddr[i] & mask[i])) {

The code needs to ensure that both remAddr and reqAddr are not too short. It makes sense to me that the code would verify the required address in the constructor and the remote address in the matches method.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume you're referring to this line. I can add a comparison that the remAddr.length * 8 >= nMaskBits, but I'm having trouble coming up w/ a too short IP address. Stuff like 192.168.1 and shorter variants seem to be matching just fine.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, I was behind a version. I'm referring to this line.

I wonder if it would break if you configured to match against an IPv6 address and called matches with an IPv4 address?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jzheaux In that case this line will realize that the classes of the IP addresses are different (java.net.Inet6Address vs java.net.Inet4Address) and then simply return False. IMO this feels more correct than an IllegalArgumentException stating that a mask length is too long, which isn't indicative that the addresses you're comparing are of different types. Unless it is valid to try to mix and match ipv4 and ipv6 addresses?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jzheaux In that case this line will realize that the classes of the IP addresses are different (java.net.Inet6Address vs java.net.Inet4Address) and then simply return False. IMO this feels more correct than an IllegalArgumentException stating that a mask length is too long, which isn't indicative that the addresses you're comparing are of different types. Unless it is valid to try to mix and match ipv4 and ipv6 addresses?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it's not a valid use case -- was just thinking out loud about how you might make the remote address byte array too long.

I agree that an IPv4Address instance will always be 4 bytes long and an IPv6Address will always be 16 bytes long, so there's no need to check the length of remote address.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @jzheaux, any other feedback?

@jzheaux jzheaux self-assigned this Jul 9, 2019
@jzheaux jzheaux added in: web An issue in web modules (web, webmvc) status: duplicate A duplicate of another issue status: waiting-for-feedback We need additional information before we can continue type: improvement and removed status: waiting-for-triage An issue we've not yet triaged labels Jul 9, 2019
@jzheaux jzheaux added this to the 5.2.0.RC1 milestone Jul 9, 2019
@jzheaux jzheaux added type: enhancement A general enhancement and removed type: improvement labels Jul 9, 2019
@clementkng clementkng force-pushed the gh-2790-ip-address-matcher-array-length-checks branch from dc38ca4 to be57e8f Compare July 9, 2019 18:38
@@ -46,15 +47,18 @@
*/
public IpAddressMatcher(String ipAddress) {

String ipAddr = ipAddress;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While this may be an improvement, @clementkng, let's please leave renaming the variable for another PR, unless there is a reason it's necessary?

Copy link
Contributor Author

@clementkng clementkng Jul 13, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jzheaux I changed it because ipAddress is overwritten if we parse a mask, meaning that I can’t use it in a meaningful error message (to show the ip and mask together).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess an alternative would be to rewrite the message in a way i.e. IP address <address> too short for bitmask <mask>. Let me know what you think.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that a message with placeholders is a good solution. I like it because of the smaller change footprint.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jzheaux I changed the message and changed the variables back.

@clementkng clementkng force-pushed the gh-2790-ip-address-matcher-array-length-checks branch from be57e8f to 6d917c1 Compare July 13, 2019 17:47
@clementkng
Copy link
Contributor Author

@jzheaux Thanks for the review. Is there any other feedback?

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Jul 17, 2019
@@ -76,6 +80,8 @@ public boolean matches(String address) {
byte[] reqAddr = requiredAddress.getAddress();

int nMaskFullBytes = nMaskBits / 8;
Assert.isTrue(remAddr.length >= nMaskFullBytes,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, this check can be removed, correct @clementkng? You and I could not find a use case where this check would fail.

I'd recommend taking it out; however, if it stays, then let's make sure that the error messages align to both include the ip address and the bitmask length.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jzheaux good catch, forgot about that! I removed the check.

@clementkng clementkng force-pushed the gh-2790-ip-address-matcher-array-length-checks branch from 6d917c1 to a80944e Compare July 18, 2019 14:20
@jzheaux jzheaux merged commit ab6440d into spring-projects:master Jul 19, 2019
@jzheaux
Copy link
Contributor

jzheaux commented Jul 19, 2019

Thanks, @clementkng! This is now merged into master.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: web An issue in web modules (web, webmvc) status: duplicate A duplicate of another issue status: feedback-provided Feedback has been provided type: enhancement A general enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

SEC-2576: ArrayIndexOutOfBoundsException in IpAddressMatcher
3 participants