- Notifications
You must be signed in to change notification settings - Fork1
A powerful toolkit for enforcing access restrictions in Java
License
MeGysssTaa/access-warden
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Access Warden is a simple to use yet powerful toolkit designed to allow Java developers toenforce access restrictions in their applications. It works by generating special runtime stacktrace and environment inspection code and injecting it in your classes after build.
Let's imagine we're developing a game. Let's say we have a classPlayer
with this method:
privatevoidjump() {this.posY +=1.0;// (some hyper-realistic physics simulation here)}
Assuming this method is only called from inside ourPlayer
class, we can define itprivate
. This means that we are protected from all other classes/sources accessing this method and causing the player to jump infinitely... or,are we?
Actually thejump
method can still be accessed byany other third-party. For example, anattacker can usereflection for that:
voidhack() {Playerplayer = ...Class<?>clazz =Class.forName("our.cool.game.Player");Methodmethod =clazz.getDeclaredMethod("jump");method.setAccessible(true);method.invoke(player);// here, we bypass the "private" access restriction}
Additionally, anattacker could potentially use some native (C/C++) tricks and possibly even something more to ignore theprivate
keyword you've just put so much effort in writing. This is definitely not something most applications should worry about. But some certain kinds of applications actuallydo want to avoid the possibility of such"attacks".
One way of getting around this is to use aSecurityManager
, either by defining one before launching your application (which also has to be enforced somehow) with some pre-defined security policies files, or programmatically, by directly inheriting fromjava.lang.SecurityManager
and writing code that will filter all the forbidden calls on your own (which may be incompatible with user's current environment, say, due to anotherSecurityManager
being already set). Both options involve comparably much work and have severe drawbacks.
Access Warden provides a toolkit that helps you deal with this kind of issueeasily, quickly, and comparably reliably. Here's some brief overview of allAccess Warden modules:
- API — Provides low-level access to stacktrace/environment inspection and allows you write somereally specific checks suitable for your particular application case. However, in most cases you'll be only including this module forannotations, on which the other modules are based.
- Core — Provides very high-level, control-less access toJVM bytecode generation in existing JAR files. Mostly used either as a standalone application or by other modules (such as the Gradle module) for transformation of existing (built) application JAR files. However, you can also use it to run JAR transformations programmatically, at a high level (with barely writing any code).
- Gradle — Removes the need in running the Core module as a standalone application after each application build. Instead, all the necessary transformations will be automatically applied after you build your application with Gradle.
- Demo — A basic runnable example that demonstrates the wayAccess Warden can be used, uses Gradle.
WithAccess Warden, our examplePlayer#jump()
method can be secured somewhat as follows:
@RestrictedCall (prohibitReflectionTraces =true,prohibitNativeTraces =true,prohibitArbitraryInvocation =true,permittedSources = {"my.cool.game.Player#update*","my.cool.game.Player#keyPressed" })privatevoidjump() {this.posY +=1.0;// (some hyper-realistic physics simulation here)}
After building this code, the annotation above thejump
method will be removed from the code (you can change this behavior to keep the annotation, if you need to, though), and instead some special code will be generated and inserted in the beginning of the method instruction set. This special code will onlyallow methodkeyPressed
and all methods whose name starts withupdate
(e.g.updateInputs
,updatePhysics
, etc.) from inside classmy.cool.game.Player
to pass. Additionally, it willforbid thejump
method to be invoked with reflection and/or native methods.
Any calls that do not match the described criteria will cause aSecurityException
to be thrown. This means that you nowtruly define who can, and who cannot access yourPlayer#jump
method. Moreoever, it's really easy to do and doesn't require you to have any special knowledge (other than details specific to your application).
Note that with this annotation, you no longer even have to make your methodprivate
—public
will act pretty much the same. However, this isnot recommended, since it violates the basics of OOP and makes your code difficult to understand by causing an illusion of apublic
method that is actually restricted.
It does so by simply injecting special bytecode in your already compiled JAR files that throws ajava.lang.SecurityException
if the method call is not permitted. The exception will carry a message describing theexact reason why the call was suspended (e.g. whether the caller source was explicitly blacklisted, or the caller used reflection which was disabled for this method via configuration).
For detailed installation instructions and "how to use" see theGetting Started page of the Wiki. For specific details you can also see documentation/javadocs. There's also a lot of other useful information availableon the Access Warden Wiki.
AllAccess Warden's runtime access context checks, of course, have some CPU overhead. Moreover, your final application JAR (after transformations) will be slightly increasing in size for each piece of code you annotate with@RestrictedAccess
or similar. That is, it is only adviced to useAccess Warden's power on the most vulnerable parts of your code — where anattacker bypassing regular Java access modifiers is unacceptable or extremely unwanted.
Internally, though,Access Warden attempts to generate as little amounts of code as possible. See theCode Generation page of the Wiki for details.
I can't state that the level of "protection"Access Warden offers is 100% bulletproof. But it is indeed a good starting point against"script-kiddies", and it definitely requires some special knowledge to bypass its checks, if configured and used right.
If you'd like to report a bug, ask a question, suggest a new feature, or even provide some code improvements on your own, don't hesitate toopen an issue ormake a pull request!
Assuming you already have Git, Maven, and Gradle installed and set up.
First, clone the project from git andcd
into it:
git clone https://github.com/MeGysssTaa/access-wardencd access-warden
Second, use Gradle Wrapper to build the executables (JAR files) from source:
# To build all modules at once:./gradlew build# To build one particular module (for example, access-warden-api):./gradlew access-warden-api:build
Please note that in order to build particular modules you'll first have to build the entire project. This is because modules depend on each other(API <- Core <- Gradle <- Demo).
To learn more aboutAccess Warden modules, seewiki.
About
A powerful toolkit for enforcing access restrictions in Java