forked from cosmos/cosmos-sdk
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add docs/design.md; Add sketchy for illustration
- Loading branch information
Showing
4 changed files
with
125 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
## Design Document | ||
|
||
### Object-Capability Model | ||
|
||
When thinking about security, it's good to start with a specific threat model. Our threat model is the following: | ||
|
||
> We want to assume a thriving ecosystem of Cosmos-SDK modules that are easy to compose into a blockchain application. Some of these modules will be faulty or malicious. | ||
The Cosmos-SDK is designed to address this threat by being the foundation of an object capability system. | ||
|
||
``` | ||
The structural properties of object capability systems favor | ||
modularity in code design and ensure reliable encapsulation in | ||
code implementation. | ||
These structural properties facilitate the analysis of some | ||
security properties of an object-capability program or operating | ||
system. Some of these — in particular, information flow properties | ||
— can be analyzed at the level of object references and | ||
connectivity, independent of any knowledge or analysis of the code | ||
that determines the behavior of the objects. As a consequence, | ||
these security properties can be established and maintained in the | ||
presence of new objects that contain unknown and possibly | ||
malicious code. | ||
These structural properties stem from the two rules governing | ||
access to existing objects: | ||
1) An object A can send a message to B only if object A holds a | ||
reference to B. | ||
2) An object A can obtain a reference to C only | ||
if object A receives a message containing a reference to C. As a | ||
consequence of these two rules, an object can obtain a reference | ||
to another object only through a preexisting chain of references. | ||
In short, "Only connectivity begets connectivity." | ||
- https://en.wikipedia.org/wiki/Object-capability_model | ||
``` | ||
|
||
Strictly speaking, Golang does not implement object capabilities completely, because of several issues: | ||
|
||
* pervasive ability to import primitive modules (e.g. "unsafe", "os") | ||
* pervasive ability to override module vars https://github.com/golang/go/issues/23161 | ||
* data-race vulnerability where 2+ goroutines can create illegal interface values | ||
|
||
The first is easy to catch by auditing imports and using a proper dependency version control system like Glide. The second and third are unfortunate but it can be audited with some cost. | ||
|
||
Perhaps [Go2 will implement the object capability model](https://github.com/golang/go/issues/23157). | ||
|
||
### What does it look like? | ||
|
||
Only reveal what is necessary to get the work done. | ||
|
||
For example, the following code snippet violates the object capabilities principle: | ||
|
||
```golang | ||
type AppAccount struct {...} | ||
var account := &AppAccount{ | ||
Address: pub.Address(), | ||
Coins: sdk.Coins{{"ATM", 100}}, | ||
} | ||
var sumValue := externalModule.ComputeSumValue(account) | ||
``` | ||
|
||
The method "ComputeSumValue" implies a pure function, yet the implied capability of accepting a pointer value is the capability to modify that value. The preferred method signature should take a copy instead. | ||
|
||
```golang | ||
var sumValue := externalModule.ComputeSumValue(*account) | ||
``` | ||
|
||
In the Cosmos SDK, you can see the application of this principle in the basecoin examples folder. | ||
|
||
```golang | ||
// File: cosmos-sdk/examples/basecoin/app/init_handlers.go | ||
package app | ||
|
||
import ( | ||
"github.com/cosmos/cosmos-sdk/x/bank" | ||
"github.com/cosmos/cosmos-sdk/x/sketchy" | ||
) | ||
|
||
func (app *BasecoinApp) initRouterHandlers() { | ||
|
||
// All handlers must be added here. | ||
// The order matters. | ||
app.router.AddRoute("bank", bank.NewHandler(app.accountMapper)) | ||
app.router.AddRoute("sketchy", sketchy.NewHandler()) | ||
} | ||
``` | ||
|
||
In the Basecoin example, the sketchy handler isn't provided an account mapper, which does provide the bank handler with the capability (in conjunction with the context of a transaction run). | ||
|
||
### More Resources | ||
|
||
* Read the [Cosmos SDK Guide](./guide.md). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package sketchy | ||
|
||
import ( | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
) | ||
|
||
/* | ||
This is just an example to demonstrate a "sketchy" third-party handler module, | ||
to demonstrate the "object capability" model for security. | ||
Since nothing is passed in via arguments to the NewHandler constructor, | ||
it cannot affect the handling of other transaction types. | ||
*/ | ||
|
||
// Handle all "sketchy" type messages. | ||
func NewHandler() sdk.Handler { | ||
|
||
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { | ||
// There's nothing accessible from ctx or msg (even using reflection) | ||
// that can mutate the state of the application. | ||
return sdk.Result{} | ||
} | ||
|
||
} |