Mic,
I've taken the liberty to copy paste your questions into the list below
(my apologies if I've missed some), my answers to your questions follow.
I'll apologise in advance, as I don't have time to answer more follow up
questions, perhaps others on the list might be able to assist.
Regards,
Peter.
On 17/02/2017 10:23 AM, Michał Kłeczek wrote:
There is a huge misunderstanding here.
I am pretty confident I understand and know how River works (at least
up to version 3.0 exclusive)
And my questions are not about how things are implemented but what
changes Peter is proposing.
Especially in the context of all the discussions that are held here
around security, OSGI, serialization etc.
The questions are very detailed and technical - because there is a lot
of things that are not clear
in the proposed designs.
For example - saying that "deserializing an object is secure because
it is a dynamic proxy" is simply misleading. That is why I ask more
questions.
I agree, that's a misleading statement, the words are not mine and I
don't endorse that statement.
You might call it "demanding your time" but it shouldn't stop anyone
from asking questions.
No, but there is a limit to how much time we might have available to
answer them, in other words, try not to get upset if we don't.
Cheers,
Michal
I've noticed there are roughly three discussion topics in this conversation:
1. Mic's SmartProxyWrapper - to Support OSGi, where it is proposed to
use the wrapper object to perform codebase provisioning.
2. JGDMS changes
3. Formulating a proposal to support OSGi, leveraging delayed
unmarshalling, resolving and provisioning a smart proxy bundle,
without stream codebase annotations.
Mic's Questions:
1.
I want my implementation of RemoteEventListener to be a smart proxy.
How do u support that? Context - Supporting OSGi.
2. If you allow to pass "installer" to unmarshall proxies - then the
next question is - why do you require doing it explicitly in the
application code??? Context - Supporting OSGi.
3. But then the next question is why not put it in the object stream
implementation itself??? Context - Supporting OSGi - using Mic's
SmartProxyWrapper
4. But what if the client has MULTIPLE clients - each with its own
exact API version? Context - Supporting OSGi - clients with
incompatible service api versions.
5. So your SaveUnmarshallingProxy can do input validation fist as
well, can't it? Context - I think it relates to JGDMS
6. So if the CodeDownloadingSmartProxyWrapper implements AtomicSerial
then it is fine? Context - Supporting OSGi - using Mic's
SmartProxyWrapper.
7. What is "signed codebase"? How do you encode the signature in the
codebase annotation? Context - JGDMS
8. Codebase of what service? All of them?
9. Wouldn't it be easier if you simply forbid code downloading during
unmarshalling as in SmartProxyWrapper I've shown in another
message? Context - Supporting OSGi - using Mic's SmartProxyWrapper.
10. Peter wrote:
Some of your assumptions around forbidding code downloading are
incorrect, which means the other assumptions that rely upon it
are also wrong.
Which assumptions? Context - Supporting OSGi - using Mic's
SmartProxyWrapper
11. Is use of AtomicSerial mandatory? Context - JGDMS
12. Based on what information are DownloadPermissions and
DeserializationPermissions granted? Only URL of the jar file?
Context - JGDMS
13. It seems like I am missing the high level view on the architecture
of your software.
Would it be possible for you to write one? Context - JGDMS
14. How does the client know it is "Reggie" it is talking to? Context
- JGDMS
15. How Reggie can grant itself permissions in the client
environment??? Context - JGDMS
16. What is this "token"? Is it a Java object implementing a well
known interface? What interface is it? Context - JGDMS
17.
SafeServiceRegistrar will still allow you to use your wrapper
class, it just adds an additional step of allowing you to
authenticate that service before you deserialize your service
wrapper, making it a little safer.
How???
By using the "token" you talk about earlier? But you have to
verify the token to be secure, don't you? Context - JGDMS
18. So you delegate "token" authentication to Reggie, but that
requires verification of Reggie proxy.
But how do you verify Reggie proxy? Context - JGDMS
19. Does Reggie also provide the "token"? If so - how is it
authenticated? If not - how do you authenticate reggie? Context -
JGDMS
20.
AtomicMarshalInputStream performs a special input validation on
java.lang.reflect.Proxy thus ensuring the InvocationHandler is
also trusted. If the InvocationHandler doesn't pass the test
the proxy's never created.
Why does it only verify dynamic proxies? Doesn't it verify normal
objects? Context - JGDMS
21. Context - JGDMS
1. What interface this bootstrap proxy implements?
2. Why do you think it has to be a dynamic proxy (ie. an instance
of a subclass of java.lang.Proxy)?
3. What and when are DownloadPermissions required? How do they add
to the overall security?
I understand the security of service proxies is enforced by the
constraints placed on the bootstrap proxy.
So where is the place for DownloadPermissions?
22. Context - JGDMS
4. Finally - how is the lookup service proxy verified? Does it
also provide the bootstrap proxy?
If so - what special role does it play in the architecture?
The bootstrap proxy does not have to be provided by the lookup
service, does it?
If it is verified differently - why and how?
23. What I DO NOT understand is - why the download permissions are
needed at all?
Since the bootstrap proxy's code MUST be local code - why not
simply have its class
defined by the context ClassLoader? Context - Existing River feature.
24. Since downloading code is done only after authentication anyway -
I don't see the reason to
use DownloadPermissions at all.
The only thing that comes to mind is that it is to make sure the
service
is not able to download code from a codebase different than its own.
Which is OK but redundant. The reasoning is:
Since the code of the service proxy is already trusted (we have
established trust before downloading it) -
we can simply place the constraints on the service proxy that
instructs it to only download
code meeting certain criteria.
Am I correct in my thinking? Context - requires clarification.
Pete's Answers:
1. I'm not currently planning to support using remote objects (that
aren't services) that require codebase provisioning for OSGi. I'm
presently only considering supporting remote Services (exported
remote objects that are registered services). Remote event
listeners and such like that are dynamic proxy's only at this
time, without a codebase. My time is limited, if someone wants to
implement it, then that's great. Remember I haven't even begun
coding this at this time, this is all very preliminary.
2. Sorry, I've read it a few times, but still don't understand this
question.
3. The reason I don't think it's a good idea to put it in the stream
is, what if it's missing? The remote end controlls what's going
into the stream, when you deserialize, you're only parsing it, the
remote end controls which objects are placed into the stream, this
is a lot riskier if you're not taking advantage of
DownloadPermission. But having said that, it's a strategy that
would work, provided your utilising DownloadPermission and input
validation.
4. Each service api version released can have diffierent and multiple
provider implementations, clients only need to know about the ones
they're compatible with.
5. Sorry JGDMS doesn't have this feature, the answer is therefore no.
6. Yes you can use AtomicMarshalInputStream and perform input
validation with your SmartProxyWrapper, then if your invariants
aren't validated, the client can terminate the connection, the
attacker loses control of the stream, an exception is thrown and
control returns to the caller.
7. A signed jar
https://docs.oracle.com/javase/tutorial/deployment/jar/signindex.html
Httpmd can encode a message digest into your codebase annoation.
8. Yes, I'd encourage you to sign all your jar files. JGDMS allows
you to use self signed code signer certificates, but you'll still
need CA signed server and client certificates.
9. I'm sorry, I can't find where you demonstrated how to forbid code
downloading in SmartProxyWrapper. DownloadPermission is an
existing feature, and it's well proven, my personal opinion is it
would easier to use that rather than write another tool that may
create new vulnerabilities, but you are free to write one in
SmartProxyWrapper if you want.
10. I don't think you have a good understanding about how
DownloadPermission works, you are proposing replacing it with a
Serializable object in the stream with a class that's local to the
client. DownloadPermission is an existing feature of River, I
think you need to perform some further investigation.
11. No using AtomicSerial is not mandatory. Some things are more
exposed to attack, all existing River services utilise it in
JGDMS, as do the token's and it is advisable to use it, however if
you controll both ends of a secure endpoint (JGDMS TLSv1.2), then
an attacker can't send you a serialized stream if your a service
or a proxy. But it's definitely necessary for Reggie and the tokens.
12. These permissions are granted during discovery, after the lookup
service is authenticated, the lookup service returns the URL
string (can be null) and jar signer certificates (may be null) and
these will be granted DownloadPermission and
DeserializationPermission. However these permissions will not be
granted if both are null. See hyperlinks below.
13. Do you have any links of examples of what you're after?
14. Reggie is authenticated, so you know it's Reggie you're talking
to, if Reggie can't be authenticated, we don't talk.
15. If you use GrantPermission you can allow Reggie to grant
permission to itself. This isn't something that I'd encourage or
condone however. This is existing River functionality. As
mentioned above JGDMS first authenticates the connection to Reggie
during discovery and only grants permission if authentication is
successful.
16. The token is an instanceof java.lang.reflect.Proxy, containing one
of JERI's InvocationHandler's, the interfaces it implements are
defined here:
https://github.com/pfirmstone/JGDMS/blob/Maven_build/modularize/JGDMS/jgdms-lib-dl/src/main/java/net/jini/lookup/SafeServiceRegistrar.java
17. Yes, authentication occurs when the token makes a connection, you
need to apply a minimum principal constraint.
18. No, client authentication is not performed by reggie. The
client's proxy preparer performs authentication using the tokens
retrieved from the lookup service. ServiceDiscoveryManager is
used in this instance to prepare the lookup service, the
functionality in River that applies a proxy preparer to the lookup
service is still there and utilised via configuration.
19. Reggie's proxy retrieves the token from a service when it
registers with the lookup service. The authentication questions
I've already answered above.
20. java.lang.reflect.Proxy doesn't implement AtomicSerial, so it must
be validated by AtomicMarshalInputStream, same goes for other
utilised java platform classes. Classes implementing AtomicSerial
are responsible for validating their own invariants.
21. .1 See the answer to question 16 above. 2. java.lang.reflect.Proxy
appealed to me at the time, as it can utilise existing JERI
endpoints for authentication. 3. DownloadPermission is part of
the Jini platform, I've provided some answers already regarding
DownloadPermission, I'll let you do some more investigation in
your own time.
22. Well, first the discovery process makes contact with the lookup
service using the discovery protocol, then the lookup service is
authenticated over a secure connection, then the lookup proxy is
granted download permission and deserialization permission, to
it's URL & signers, then it is downloaded, the proxy implements
AtomicSerial and validates input. The discussion about
bootstrap proxy isn't relevant here. The ProxyPreparer used by
ServiceDiscoveryManager remains and has the same function as River
/ Jini. The only change JGDMS makes in discovery is allow for
DownloadPermission and DeserializationPermission to be granted
dynamically after authentication. There are some new discovery
providers with improved security, but are just basically the same
as River / Jini.
23. I'll leave it as an exercise for you to investigate why
DownloadPermission is required, this is part of River / Jini.
24. Same as question 23 regarding DownloadPermission.
JGDMS shouldn't be seen as a new architecture, think of it as River with
fixes for a number of security bugs and some neat features inspired by
some long time River / Jini users who've expressed their ideas on the
dev list, without whom, they wouldn't exist.
https://pfirmstone.github.io/JGDMS/
https://github.com/pfirmstone/JGDMS/blob/Maven_build/modularize/JGDMS/jgdms-discovery-providers/src/main/java/org/apache/river/discovery/internal/EndpointBasedServer.java
https://github.com/pfirmstone/JGDMS/blob/Maven_build/modularize/JGDMS/jgdms-discovery-providers/src/main/java/org/apache/river/discovery/internal/EndpointBasedClient.java
https://pfirmstone.github.io/JGDMS/doc/api/org/apache/river/discovery/ssl/sha224/package-summary.html
https://github.com/pfirmstone/JGDMS/blob/Maven_build/modularize/JGDMS/jgdms-discovery-providers/src/main/java/org/apache/river/discovery/ssl/sha256/package.html