-
Notifications
You must be signed in to change notification settings - Fork 578
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
Add new rule REFL_REFLECTION_INCREASES_ACCESSIBILITY_OF_CLASS #1541
Conversation
securityCheck = true; | ||
} | ||
} catch (ClassNotFoundException e) { | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There probably should be at least a comment here explaining why we take no action.
spotbugs/etc/messages.xml
Outdated
a class in a package provides a public method which takes an instance of java.lang.Class as its parameter and | ||
calls its newInstance() method then it increases accessibility of classes in the same package without public | ||
constructors. An attacker code may call this method and pass such class to create an instance of it. This should | ||
be avoided by either making the method non-public or by invoking SecurityManager.checkPackageAccess on the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The security manager is being deprecated and will be removed (see JEP 411).
spotbugs/etc/messages.xml
Outdated
package. A third possiblity is to use the java.beans.Beans.instantiate() method instead of | ||
java.lang.Class.newInstance() which checks whether the Class object being received has any public constructors. | ||
be avoided by either making the method non-public or by checking for package access permission on the package. | ||
A third possiblity is to use the java.beans.Beans.instantiate() method instead of java.lang.Class.newInstance() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Misspelled "possibility"
c2ff2bb
to
34430ab
Compare
Sorry for force pushing but there was a git mess which I had to sort out. |
@@ -0,0 +1,82 @@ | |||
/* | |||
* FindBugs - Find bugs in Java programs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New files should use a SpotBugs copyright notice, not FindBugs.
commit 54e0306 Author: Ádám Balogh <adam.balogh@ericsson.com> Date: Wed Jun 30 20:04:00 2021 +0200 Comment header updated from FindBugs to SpotBugs commit 34430ab Author: Ádám Balogh <adam.balogh@ericsson.com> Date: Fri May 14 11:18:04 2021 +0200 Nullness check for returned JavaClass instance added commit 0b10681 Author: Ádám Balogh <adam.balogh@ericsson.com> Date: Fri May 14 11:03:56 2021 +0200 Fixed typo in messages.xml commit d9ae166 Author: Ádám Balogh <adam.balogh@ericsson.com> Date: Mon May 10 13:07:45 2021 +0200 Added report for missing class and long description rephrased commit 2c5aa45 Author: Ádám Balogh <adam.balogh@ericsson.com> Date: Fri May 7 15:25:20 2021 +0200 Add new rule REFL_REFLECTION_INCREASES_ACCESSIBILITY_OF_CLASS SEI CERT rule SEC05-J forbids the use of reflection to increase accessibility of classes, methods or fields. If a class in a package provides a public method which takes an instance of java.lang.Class as its parameter and calls its newInstance() method then it increases accessibility of classes in the same package without public constructors. An attacker code may call this method and pass such class to create an instance of it. This should be avoided by either making the method non-public or by invoking SecurityManager.checkPackageAccess on the package. A third possiblity is to use the java.beans.Beans.instantiate() method instead of java.lang.Class.newInstance() which checks whether the Class object being received has any public constructors. This patch adds a new detector to check this rule.
SEI CERT rule SEC05-J forbids the use of reflection to increase accessibility of classes, methods or fields. If a class in a package provides a public method which takes an instance of java.lang.Class as its parameter and calls its newInstance() method then it increases accessibility of classes in the same package without public constructors. An attacker code may call this method and pass such class to create an instance of it. This should be avoided by either making the method non-public or by invoking SecurityManager.checkPackageAccess on the package. A third possiblity is to use the java.beans.Beans.instantiate() method instead of java.lang.Class.newInstance() which checks whether the Class object being received has any public constructors. This patch adds a new detector to check this rule.
54e0306
to
604d132
Compare
@KengoTODA Rebasing done, also moved line in CHANGELOG.md to ###Unreleased. |
@KengoTODA It seems that you approved this one. Are there any obstacles in merging it? |
@baloghadamsoftware thanks for reminding me. Could you merge |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Current implementation catches just limited cases and will trigger false positives (expected reflection access). We need a more complicated analysis to make this detector productive.
And please merge the latest master
branch, to resolve conflict in the CHANGELOG.md
.
|
||
@Override | ||
public void sawOpcode(int seen) { | ||
if (seen == Const.INVOKEVIRTUAL) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better to exit method to reduce nest, so I suggest moving securityCheck
confirmation to here like below:
if (securityCheck || seen != Const.INVOKEVIRTUAL) {
return;
}
if (!securityCheck && obj.isInitialParameter() && "java.lang.Class".equals(cls.getClassName()) && | ||
"newInstance".equals(met.getName()) && "()Ljava/lang/Object;".equals(met.getSignature()) && | ||
getMethod().isPublic()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel these conditions are not so suitable to detect the target defect. What we need to avoid is increasing accessibility, but this method does not check the accessibility of the constructor and the target class.
… condition to check whether the class is public as well.
Thank you for taking you time to do a second review on this PR. I merged master into this PR and also fixed the CHANGELOG. Furthermore, I made the change in the condition check you requested and added an additional condition to work only on public classes. You are completely right, this detector is only the first step, it only catches the second non-compliant example described in the SEI-CERT rule. I originally planned to add the rest in a subsequent PR. Should I do it now, in this particular one? I tested this on several open-source projects, as you can see above and could not find any false positives, Could you suggest me an example project where we get the false positive you mentioned? What more complex analysis do you suggest? Actually, a public method in a public class can be called by anyone, even outside the package. If such a method takes a class as its parameter and instantiates it without any security check then we can call it a vulnerability because anyone can pass it a class that is not meant to be instantiated by any other class, just some special classes. We cannot check the actual "increase" because we must be able to detect the vulnerability itself, without the attacker code being present. Thus at the time of the analysis we are not aware of the actual parameter passed to the method. Maybe we should change the error message to contain the "potential" word? |
Hmm, maybe REFL_REFLECTION_MAY_INCREASE_ACCESSIBILITY_OF_CLASS? |
Because of field summaries some fields may also be initial parameters if they are initialized from constructor parameters. Let us exclude them!
The SEI CERT rule also mentions two uncompliant code pieces where accessibility of fields are increased. This patch extends the detector to also report these cases: REFL_REFLECTION_MAY_INCREASE_ACCESSIBILITY_OF_FIELD.
One out of the three findings on MATSim-Libs and one out of the two findings on NanoHTTPD were actually false positives beause |
spotbugs/etc/messages.xml
Outdated
@@ -8676,4 +8717,5 @@ after the call to initLogging, the logger configuration is lost | |||
<BugCode abbrev="DL">Unintended contention or possible deadlock due to locking on shared objects</BugCode> | |||
<BugCode abbrev="JUA">Problems in JUnit Assertions</BugCode> | |||
<BugCode abbrev="EOS">Bad End of Stream check</BugCode> | |||
<BugCode abbrev="REFL">Reflection increasing accessibility of classes, methods and fields</BugCode> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better to add another BugCode
element even in the findbugs.xml
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean that I should use two different bug codes for the two kinds of bugs? I changed them now to REFLC and REFLF.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean that I should separate the bug codes? I did it, now we have REFLC and REFLF.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean you need to add <BugCode>
element in another file. Both messages.xml
and findbugs.xml
have <BugCode>
element.
spotbugs/src/main/java/edu/umd/cs/findbugs/detect/ReflectionIncreaseAccessibility.java
Show resolved
Hide resolved
spotbugs/src/main/java/edu/umd/cs/findbugs/detect/ReflectionIncreaseAccessibility.java
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks for your contribution! I will keep this PR open for a while, to get more feedback from the team.
@baloghadamsoftware Please resolve conflict, probably around |
6b1c02a
Done. |
SEI CERT rule SEC05-J forbids the use of reflection to increase
accessibility of classes, methods or fields. If a class in a package
provides a public method which takes an instance of java.lang.Class as
its parameter and calls its newInstance() method then it increases
accessibility of classes in the same package without public constructors.
An attacker code may call this method and pass such class to create an
instance of it. This should be avoided by either making the method
non-public or by invoking SecurityManager.checkPackageAccess on the
package. A third possiblity is to use the java.beans.Beans.instantiate()
method instead of java.lang.Class.newInstance() which checks whether the
Class object being received has any public constructors.
This patch adds a new detector to check this rule.
Change-Id: I1881502512848f8a04b7ee6be95539f5fe88c6b3
Make sure these boxes are checked before submitting your PR -- thank you!
CHANGELOG.md
if you have changed SpotBugs code